Building components that are accessible by default
The cost difference between building a component accessibly the first time and retrofitting it later isn't marginal — it's usually an order of magnitude, because retrofitting means touching every place the component is already used, re-testing all of them, and often discovering the visual design assumed a DOM structure that doesn't map cleanly to the accessible one.
The single highest-leverage habit: build on top of unstyled, accessible primitives (Radix, React Aria, or similar) rather than styling raw HTML elements from scratch. These libraries handle the parts that are easy to get subtly wrong — focus management in a dialog, roving tabindex in a menu, correct ARIA relationships in a combobox — so your team's code only has to handle visual styling and content.
For anything built from scratch, the two checks we run on every new component before it ships: can you complete every interaction using only a keyboard, and does a screen reader announce state changes (expanded, selected, loading) without requiring the user to guess. Both are fast manual checks, and both catch problems automated tools consistently miss.
Document the accessibility contract of a component alongside its props — what ARIA attributes it manages internally, what the consumer is responsible for (like providing an accessible name), and what keyboard interactions it supports. This turns accessibility from tribal knowledge into something a new engineer can verify without asking.