A brief introduction:
I've been building React.js and Next.js apps for three years. I've also dabbled in React Native, Flutter, and recently Web Components. While each of these comes with its own unique challenges, there are a few principles that you should keep in mind when building user interfaces.
The following is a set of guiding principles that will help you improve your UI within and beyond the browser. I divided these principles into two categories: must have and good to consider.
Must have
1. Make it responsive
Let's start with the obvious: screens come in a wide range of sizes, and everything you build should be responsive. For many people, this means popping open Chrome developer tools, toggling mobile device emulation, and calling it a day. However, there is more to consider.
a) How does my app handle touch input?
I'm guessing most of us are still using laptops (or other keyboard/mouse controlled devices) to build websites. When you open Chrome's mobile device emulator, you are simulating touch, but keep in mind you are still using a mouse as your pointing device. Consider the preciseness of a mouse compared to your finger. Take some time to test your website using your phone instead of simulated touch input.
b) What does my app look like on large screens?
You should be thinking mobile-first, but it's also good to consider the other extreme: large screens. Take some time to test your app on a large monitor. Consider what happens when your website goes really wide and whether the content should also go wide. Remember that wide paragraphs are harder to read. Consider constraining the width of the content on your site. A good rule of thumb is paragraphs should wrap at roughly sixty characters wide.
c) Does my app respond to the browser window being resized?
Sometimes pure CSS can't do the job, and we have to reach for JavaScript to lend a helping hand. Say you are using JavaScript to calculate the width of an element. Does the element width need to be recalculated if the user resizes the browser window? Consider listening for the window resize event or using a resize observer to trigger a recalculation of the element's width.
d) Use rem for your fonts
Using rem
as your unit for fonts allows text to adapt to the system font size. This allows users to increase text size across all websites. You could even combine rem
and vw
to get something like font-size: calc(1rem + 1vw)
, which would give you a font size that is configurable by the user and adaptable to larger screen sizes.
2. Make it accessible
It's easy to tell yourself that you will make something accessible later. However, accessibility will help dictate how you build something. In my experience, it's better to address accessible as you go. I've found that focusing on accessibility benefits everyone – not just individuals with accessibility needs. For example, making something accessible means supporting standard keyboard interactions, which anyone that visits your site might expect intuitively (e.g., forms should submit when enter is pressed).
Consider this a PSA: accessible user interfaces are more robust in general.
a) Can I navigate my site using only a keyboard?
This is important for accessibility, but it's also important since users will expect your UI to respond to specific keyboard interactions. For example, you should be able to tab through all focusable elements on a page.
PSA: DO NOT remove outlines (e.g., outline: none;
) unless you replace them with something equivalent! Even then, you probably shouldn't do it.
If you really must remove outlines, read this article on how to hide outlines accessibly.
b) Am I relying on color to distinguish the state of my UI?
Not everyone sees color the same way! If you can't envision what your UI will look like in grayscale, try toggling your phone black and white and see if you can easily navigate your UI without color.
Want to take this to the next level? Consider using a tool like Storybook with the @storybook/addon-a11y
add-on to simulate visual impairments.
c) Can I native my site using only a screen reader?
You can spend all day trying to understand how someone with a visual impairment might navigate your site, but why not use an actual screen reader? Most computers should have a built-in screen reader you can enable easily. You will be surprised how quickly you spot accessibility issues when using a screen reader. If you really want to take this to the next level, you can try closing your eyes, so you are completely relying on the screen reader to navigate the site.
d) Are my images labeled correctly?
Not everyone can see the images on your site. Ask yourself, is this image purely decorative, or if this image was invisible, would it negatively impact a user's ability to navigate the content of my site? Most of the time, it's the ladder, and you should include alt text that describes the content of your image.
e) Consider adding skip nav
As you move from page to page, does your focus reset to the top of the screen after each page load? Do you need to tab through the entire navbar each time the focus resets to get to the page's content? Consider adding a skip nav link as the first focusable element that allows the user to quickly jump to the main content of the page.
f) Can users focus content that isn't visible?
Is it possible for someone to tab focus an element that is not visible? One example would be a modal where the user is able to tab focus an element outside of the modal. Make sure that you trap focus within your modal, BUT don't forget to include a focusable close button so your user can exit the modal using only a keyboard – in other words, don't accidentally create a keyboard trap! You could take this to the next level and allow users to close the modal using the escape key.
d) Style your text responsibly
It's better to not overdo the fonts. Using system fonts gives you faster page loads (less data to download) and renders text the way the user is used to seeing on their system. It's also tempting to use ALL CAPS stylistically. Do so sparingly since uppercase words can be harder to read and might be misinterpreted by a screen reader as being an acronym (which are read out letter by letter).
Some other resources if you want to learn more about accessibility
- Lighthouse accessibility audits
- Keyboard accessibility checklist
- Try this keyboard accessible drag and drop
Good to consider
3. Scope your CSS
If style scoping is a term you are unfamiliar with, it usually refers to a practice where a styling library automatically generates unique class names.
Nobody likes unexpected behavior when programing. Don't trust yourself to create unique class names in a large-scale project. As your project grows, the chances of you using a duplicate class name also grows. Instead, use a style system that supports automatic style scoping (e.g., styled-components, css modules, styled-jsx, shadow dom if using Web Components, etc.).
4. Make it tree shakable / leverage code-splitting
If tree shakable is a term you are unfamiliar with, it refers to a feature built into bundlers like Webpack where unused code is automatically removed from the JavaScript bundle that is sent to the user. Similarly, code-splitting refers to a bundling feature where your code is divided into multiple bundle files, so the user only has to load the files required for the page they are on.
Note: Depending on what tools you are using, tree shaking and code-splitting might be handled automatically. For example, if you are using Next.js, then routes are automatically code-split.
a) Load everything as lazily as possible
Ideally, you should only load what is necessary to render the current page. In other words, be as lazy as possible when it comes to importing and defer loading anything you don't need for first contentful paint.
Most modern browsers even support lazy loading images allowing you to only load images that are currently visible within the browser viewport.
5. Make it isomorphic when possible
"Isomorphic," in this case, is a fancy word that refers to applications that run on the server (server-side render) and the client. Server-side rendering (SSR) usually means rendering your app server-side using Node.js – without access to browser APIs – then hydrating (handing off) your app to a browser where the user can interact. With frameworks like Next.js gaining in popularity, chances are you might want to SSR your React app at some point. I'm using React as an example, but other front-end libraries like Svelte and Vue.js also support SSR.
b) Where and when do you access browser-only APIs?
Ask yourself, would the code you're writing throw when run outside of the browser environment (e.g. if you ran it using Node)? Usually, it's safe to include code that accesses browser-only APIs as long as you call that code conditionally (e.g., if (typeof window !== 'undefined') ...
). In other words, defer running functions that access browser-only APIs until that code reaches the client.
a) Server Side Rendering in React
If you are using React, make sure you aren't referencing window
at the top level of your function component or within useMemo
. However, you can safely access window
within useEffect
and useCallback
(as long as you don't invoke your callback during the initial render).
Conclusion
If you only take two things away from this article, you should focus on making your UI responsive and accessible.
...And again, don't remove outlines (aka the focus ring)! I'm looking at you Ant Design 👀
Top comments (0)