Accessibility-First Tool Concepts

· Accessibility, Workflow · Patrick Smith

Twice now I’ve created desktop apps for designing UIs. Neither shipped and I know I want to return to this space again.

My current thinking is that accessibility is a must, and is something tools today severely lack. They are visual-first and often visual-only. Why aren’t we thinking about accessibility at the early design stage?

Doing so would both make implementation easier as we aren’t just bolting accessibility needs at the end. And faster too if we get it right from the beginning.

I think getting developers (tricking them almost) to use accessibility affordances for their own needs (for example writing tests) is an interesting way to get them to care more about it.

Here are some tooling ideas:

Emulate Screen Reader Output

  • Supports VoiceOver, JAWS, NVDA.
  • Turns HTML into what would be spoken by a screen reader.
  • Can validate what actual screen readers would interpret, without having to run all of them.
  • Can use in Snapshot tests to ensure implementations are accessible and don’t break due to changes.

Screen reader emulator as CLI

  • Run with URL.
  • It streams back a screen reader representation of the page.
  • Actually might be useful for developers for browsing a website.

OCR automated testing with contrast / colour checking

  • Takes text and a role as input.
  • Renders using Playwright, and uses OCR to find the element visually on the page.
  • Only work if text passes expected contrast and colour requirements. e.g. “Can’t read button ‘Sign Up’ as it lacks contrast”.

Accessibility-first prototyping tool

  • Content is usually what differentiates your brand, what the user reads, what matches user’s existing language.
  • Write the content first, and what fundamental accessible widgets you want used.
  • See a live preview without writing any code — for visual users and for screen reader users.
  • Export a set of automated tests to verify your actual implementation.

My most used commands for front-end

· JavaScript, Workflow · Patrick Smith
# Measure HTTP response time
httpstat "https://example.org/"

# Run Google’s PageSpeed Insights
npx psi "https://example.org/" --strategy=mobile

# Run Axe Core across multiple breakpoints
npx evaluatory "https://example.org/

# Optimize & minify SVG file
npx svgo <some-file.svg>

# Visualize JavaScript usage
npx bundle-wizard example.org

# Create a new TypeScript library with TSDX
npx tsdx create <project-name>

# Create a new web app with Vite
npm init vite-app <project-name> # Vue by default
npm init vite-app <project-name> --template preact
npm init vite-app <project-name> --template react

# Creates a Cloudflare Worker
npm i -g @cloudflare/wrangler
wrangler generate <project-name>

Jeremy Keith on Architects, gardeners, and design systems

· Design, Teams, Workflow · Patrick Smith

Jeremy Keith:

It’s rare to find job titles like software gardener, or information librarian (even though they would be just as valid as other terms we’ve made up like software engineer or information architect). Outside of the context of open source projects, we don’t talk much about maintenance. We’re much more likely to talk about making.

Anyone who’s spent any time working on design systems can tell you there’s no shortage of enthusiasm for architecture and making—“let’s build a library of components!”

There’s less enthusiasm for gardening, care, communication and maintenance. But that’s where the really important work happens.

Don’t make your developer experience improvement a tax the user pays

· Planning, Product, Teams, UX, Workflow · Patrick Smith

Sometimes it feels like we decide the developer experience is more front of mind than the user experience.

Or: DX > UX.

Why is that? Does web development today feel like such a beast that I must wield a powerful weapon with which to conquer it?

We need the latest browser features to build web apps. If they are not available in every user’s browser, we will write the code we prefer and transpile or package it up into to a common lingo.

The team really wants to use this new language or framework, so we should adopt it and be cutting edge! We’ll be more attractive in the industry so hiring will be easier.

It’s quicker for us to choose the same tech everyone else is using, because they have solved lots of problems that make it sometimes tricky and there’s a huge ecosystem of ready-to-go components and plugins. We’ll move so fast! 💨

While I think these considerations should be discussed, where is the user here?

Will it be easier for the user? Will they move quicker than they had before? Will they be provided something ready-to-go to solve the problem they have? Will they really want to use what you’ve made? What did they need anyway?

If you have failed here for the user, or if the developer experience is more satisfying to the developers than the user experience is to the users, what has been gained? If it’s fast for the team to see changes live but slow for the user to load, that’s a tax the user is paying for. Was it worth it? Why should they pay?

As developers our natural sense is to pick up on what makes a compelling and fresh developer experience that will lead us to learn interesting new concepts and be involved in the currents of the industry. But does the user care? Are you creating a large tax for them to swallow? Will your team get swept away from the user? What value does the user get for paying that tax?

Keep the user experience front of mind. Talk with the user and measure so that you know that your UX is at least as compelling as your DX. Keep the tax from your DX choice low.

Low Overhead React

· CSS, JavaScript, Planning, React, Workflow · Patrick Smith

“React. Write reusable components. Make your data flow one way. Never directly use the DOM again.” There’s a lot of benefits that a developer gets by using React.

But React is easy to make complex. It’s so very tempting to optimize early. There are a lot of decisions left to you on how to architect your web app.

The techniques listed here will often make your React app have less work to do, and therefore run faster. Implicit performance is a benefit if it means less time later adding optimizations to claw back to a fast experience.

But the primary aim is to make your app easier to write, easier to change, and easier to debug. Less overhead for the person maintaining the code. Writing low overhead React means you can more easily focus on creating that great experience for your users, while not sacrificing the developer experience.

Low Overhead React Principles

  1. Don’t abandon CSS
  2. Choose packages carefully
  3. Ensure every component does at least one thing well
  4. Don’t let every component talk with the world
  5. Don’t attempt to optimize React rendering too early

Don’t abandon CSS

Look, CSS (or SCSS) has its limitations. JavaScript is obviously more capable as a language. But CSS is proven for its task. It is fast. It can declaratively handle focus and active and hover states, and it can handle a variety of media queries. It just works with server rendering, and is interoperable with technology choices other than React.

Use CSS variables to create reusable styles for typography, spacing, colors, and other things that are consistent across components.

html {
  --link-color: orange;
}

main a {
  color: var(--link-color);
}

You override CSS variables when rendering by using the style prop:

<article style={{ "--link-color": "purple" }}>
  …
</article>

(You can see an example like the above here: https://codesandbox.io/s/react-css-variables-chbsj)

CSS is still evolving. The standards are adding more capabilities. There are new approaches to organizing and reusability. Not to mention layout.

If you use CSS-in-JS, it doesn’t mean you are banned from using standalone CSS. Base CSS files work great for reusable styles across components.

Choose packages carefully

I’ll be honest: there are a lot of heavy packages out there. Calendars. Themeable kits that come with every UI control you can imagine. State and data structure libraries. Many of these dependencies have a big impact on the bundle size, and therefore the time your users will spend waiting for your application.

This doesn’t mean stay from them. Use some, but don’t just add all your first choices. Don’t say yes unless it really provides key value. A package that makes your experience better as a developer (let the team finish faster!) might make your users’ experience worse (let the user start slower!).

Yes, tree shaking can help improve the initial load time, but if you have large packages that you use as the foundation of your app, most of the tree will remain no matter how hard you shake it. And if the shaken out parts are soon downloaded after anyway, you might be consuming a lot of your users’ limited data. We don’t need to pretend NPM doesn’t exist. But we do need to remember that every npm add is also often adding wait time for every user.

Ensure every component does at least one thing well

Presentation vs Controller. Smart vs Dumb. Connected vs Reusable. Organism vs Molecule. There are many ways of categorizing and splitting-up components into specific roles. I’m not going to offer an opinion here because many ways work well. What I am going to ask is to make sure every component has a role it does particularly well.

You might decide this means the single responsibility principle, so that a component can only be purely HTML focused, or purely subscriber focused, or purely Redux connect focused, or purely analytics focused, etc etc. I leave that up to you, because there often is value in a component doing multiple things. If a component is a function, then it serve to reason that it can be made out of multiple other functions, and these functions can have a single responsibility.

All I request is that you ensure each component does at least one thing particularly well. For example: It’s great at producing markup. It’s great at talking to the rest of the app. It’s great at optimizing render times for this particular case. It may well do more, but at the least it is competent in some particular thing.

If it’s not doing a great job at anything in particular, if it’s trying to speak HTML and API and Redux and URL all at the same time, then it might be time to split it up. A dedicated smaller component can focus on a particular task and communicate its intent better. It’s often fine to keep it in the same file.

Don’t let every component talk with the world

A component is easiest to manage when it follows a simple contract: given some input, I will return what I want presented. Different input, different output. No other factors.

A slightly more complicated component contract is that: in addition, I will produce some side effects. I will POST to a server, I will talk to a local data store, I will add an event listener directly to the DOM.

Another more complicated variation is I will read from outside of my props. I will fetch from a server, I will subscribe to the latest changes to a local data store, I will listen to when the window changes size.

These components can get out hand. Many components start talking to many things. When hundreds of components have a direct connection with the local data store or communicate with the server. Or when the user resizes the window and many dozens of components individually want to update themselves.

I’m not advocating for a particular architecture or a particular number of communication points or set a limit to how many components are allowed to talk to the server. I’m saying be mindful of how many connections there are between components and their outside world. Otherwise a couple of simple changes in the outside world can schedule a huge amount of work.

This may not only lead to performance bottlenecks, but it will also make debugging and future changes harder. Which component made that change? If I rename or restructure this reducer, how many components had this knowledge and so will need to be updated? It’s best to make these questions easier to answer by reducing the surface area of connections.

Make smaller worlds for your components by bundling collaborators together, and then export a simpler component that will be used to hide the details and nuance inside. Add single connection points that bridge between one world and another. Add facades with small surface areas your components see, that then go and talk to the larger world, translating back and forth. Don’t just let any random component talk to whatever it likes. It might feel convenient now, but it’ll likely become inconvenient when changes are needed.

Don’t attempt to optimize React rendering too early

Don’t optimize your components until there’s a clear problem to be solved. React is designed so that straight forwardly written components will lead to great performance!

If do you want to apply optimizations, first read the documentation provided:

If these don’t answer your question, then reach out to people from the React core team like Dan Abramov who happily answers people’s questions on Twitter.

Next, measure using the open source React DevTools which is available for Firefox and Chrome.

Measure the current profile by clicking record, performing the particular flow that you wish to make more performant, then stopping the record. Use the interactive charts to see the bottle necks and which components need attention.

Make changes, and profile again. It may take several iterations because your expected optimization technique might make things slower.

If you have existing optimizations like React.memo in place, it might be worth removing them all, and then using the React DevTools profiler to introduce them where you see a meaningful improvement.

Using React.memo relies on every prop passed to a component staying the same (being referentially equal) across renders to skip its own rendering. This can be infectious, leading to all your components having to follow this extra contract on their props coming in. Trying to make everything referentially equal can be a lot more computational work that can lead to other performance overheads. And it’s very easy to pass just a single prop that does not stay consistent (say an arrow function), leading to the intended optimization being never applied.


React. It’s unique selling point is that it makes writing web apps easier. Yet it’s easy with React to find yourself battling complexity, or for users to be getting penalised performance. Being mindful about the overhead that some techniques and third party packages bring helps keep complexity low, performance easy to find, and future changes maintainable.