Most of the web still fails basic accessibility checks. WebAIM’s 2026 analysis of the top one million home pages found detectable WCAG 2 failures on 95.9% of them.

Six error types account for 96% of all detected errors. Three of them are failures of individual controls, and they’re about as basic as it gets: missing form labels, plus empty links and empty buttons.

Closing that gap is what UI component best practices are for. They’re the rules that keep a reusable interface element consistent and accessible across a product, and cheap to maintain: single-purpose structure, role-based names, a defined state set, tokenized styling and WCAG 2.2 conformance. The yardstick is the Web Content Accessibility Guidelines (WCAG) 2.2, along with the platform guidelines from Apple and Google. Practice lags far behind both.

How should a UI component be structured?

Each component gets one job and is built on native HTML elements. Variation travels through props or slots, not through copies of the component.

Get this wrong and every later rule, from naming to accessibility, gets fixed once per copy.

One component, one job

A component that does two things collects two sets of bugs.

Brad Frost ties small components to the single responsibility principle in his book Atomic Design (2016). Simple units are easier to test and reuse, and they keep the interface consistent.

A boolean prop that flips what the component is for is the loudest warning sign. Props that only make sense in pairs, or a name that needs “and” in it, usually mean the same thing.

Atomic design levels as a naming aid

At the bottom sit atoms, which are single HTML elements such as a label, an input or a button. Combine a few and you get a molecule, say a search form built from all three of those acting as one unit.

Organisms are the bigger sections, like a header with logo, navigation and search, or a product grid repeating one product card. Templates and pages come last. Those are components placed in a layout and then filled with real content, which is how you find out whether the system holds up.

The five levels of atomic design give a team shared words for hierarchy. Frost is explicit that it is not a linear process, but a mental model for seeing the whole interface and its parts at the same time.

The names are optional. GE Design dropped the chemistry vocabulary after colleagues found it confusing and settled on Principles, Basics, Components, Templates, Features and Applications, a case Frost’s book quotes.

Is responsive design still a top priority?

Explore the latest responsive design statistics: adoption rates, performance impact, user behavior, and trends shaping modern websites.

See the Numbers →

Props, slots and children

Native elements come first. Frost’s atoms are plain HTML elements, so a button component should render a real button and a link component a real anchor.

Composition then decides how much the component needs to know about its content.

Go the configuration-heavy way and you end up with one component and a pile of boolean props, with another one added for every new use case. Composition-first works the other way around. Slots or children carry the content, and props describe only appearance and behavior.

Pick composition. Props stay for what the component itself needs to know.

How to name UI components, variants and props

Name a component for what it does and write it in PascalCase in code. Variant and prop names should match exactly between the design file and the codebase.

Component names

React’s documentation says to start component names with a capital letter, because lowercase JSX tags are read as built-in elements. The same convention applies when you extend or wrap components from a React component library, so your custom components and the library’s components follow one consistent naming pattern.

The bigger decision is function over appearance. DangerButton beats RedButton because the name survives a rebrand. ProductCard beats Card2 for the same reason, and ConfirmDialog beats ModalNew because the name describes the job, not the history.

A name that needs a version suffix usually hides a missing decision about variants.

Variant and prop names

Open edX’s Paragon design system tells contributors to base a variant on behavior, not appearance, and to use boolean props only for features that are fully on or fully off, such as isClickable or hasCloseButton.

Designers and developers then describe the same component with the same words, which only works if the variant property names in the design file are identical to the props in code.

Skip names like “Style 2”. They say nothing about when to use the variant.

CSS class names

BEM splits a class name into a block, an element and a modifier, written as .block, .block__element and .block--modifier.

Inside a stylesheet, BEM keeps CSS selectors flat. The official BEM guide marks a selector such as .block .block__elem as bad practice and describes modifiers as flags for appearance, behavior or state.

Length is the catch. .block__elem--mod grows fast, and BEM says nothing about prop or file names.

Which states does every interactive UI component need?

Every interactive component needs default, hover, focus, active, disabled, loading and error states, and any component that shows data adds an empty state.

Shoptet’s design system documentation lists default, hover, focus, active and disabled, and Material Design adds pressed and dragged.

Default is the resting appearance, the one every other state gets measured against. Hover is pointer feedback and simply doesn’t exist on touch screens. Focus marks the keyboard position, and it has to be visible, always. Active (or pressed) covers the moment of activation.

Disabled means not operable, and it’s exempt from the 3:1 non-text contrast rule. Loading signals work in progress, with repeat submits blocked. Error flags invalid input and states the problem in text.

These apply to every one of the interactive elements in a library, which is why the state set belongs in the component spec and not in each screen.

State or variant?

States come and go. A variant is a stable configuration.

Think hover, focus, disabled and loading for states, and primary, secondary and compact for variants. Mixing the two is how a button ends up with a “disabled-primary-small” variant instead of three independent properties.

Where state styling and contrast collide

Material Design’s guidance on states draws a disabled component at 38% opacity of its enabled state. WCAG 1.4.11 exempts inactive components from the 3:1 non-text contrast requirement, so that treatment is allowed.

Allowed does not mean readable. A disabled control with no explanation leaves users guessing what unlocks it, so pair it with visible text that says what is missing.

Shoptet’s guidance asks that all states meet contrast ratios and stay perceivable in both light and dark themes. It also asks error and success states to pair color with a second cue, such as an icon, a text label or a border style.

Color alone never carries a state.

What accessibility requirements apply to UI components?

A custom component must expose its name, role and value to assistive technology, show visible keyboard focus, and meet 4.5:1 contrast for text and 3:1 for the borders, icons and state indicators that identify it.

Standard HTML controls already meet the first requirement when used according to specification, per W3C’s guidance on SC 4.1.2. The work starts when a team builds its own.

Success criterionWhat it asks forLevel
SC 4.1.2 Name, Role, ValueEvery user interface component exposes all threeA
SC 1.4.3 Contrast (Minimum)4.5:1 for text, 3:1 for large textAA
SC 1.4.11 Non-text Contrast3:1 for the parts of a control needed to identify it and its states, with inactive components exemptAA
SC 2.4.11 Focus Not Obscured (Minimum)The focused component is not entirely hidden by author-created contentAA, new in WCAG 2.2

Native HTML before ARIA

Use the native element. It ships with the role, focus handling and keyboard behavior that a custom version has to rebuild by hand.

That is the first rule in W3C’s Using ARIA guide: if HTML already has the semantics and behavior you need, use it instead of adding a role to another element. W3C has discontinued the guide as a draft and keeps the rules for reference, pointing to the ARIA Authoring Practices Guide (APG) for current guidance.

Roles, states and properties from ARIA change what assistive technology announces, but they add no behavior. The APG calls a role a promise, since a div with role="button" commits its author to supplying the keyboard interactions of a button.

WebAIM’s 2026 Million report found home pages with ARIA averaged 59.1 detected errors against 42 for pages without it. It also found that 22% of the ARIA menus it detected introduced barriers.

WebAIM notes this does not prove ARIA caused the errors, since those pages are also more complex.

W3C allows ARIA in a few cases. It’s justified where HTML has no equivalent, such as tabs, or where the native feature exists but browsers or assistive technology don’t support it properly. The third case is a design that can’t use the native element because it can’t be styled as required.

Keyboard behavior and visible focus

Every interactive control must work from the keyboard. For a button role, that means it takes focus and activates on both Enter (Return on Mac) and Space.

The APG patterns and its guidance on developing a keyboard interface define the expected keys for each widget type.

WCAG 2.2 stacks several rules on focus. SC 2.4.7 requires a visible indicator, SC 1.4.11 sets 3:1 contrast for it, and SC 2.4.11 fails when author-created content, such as a sticky header or a banner, hides the focused component entirely.

Contrast for text and component parts

WebAIM’s 2026 Million report found low contrast text on 83.9% of home pages, the most commonly detected failure in the sample.

In a component library that is a token problem, not a page problem. A color pair that fails in the button fails everywhere the button appears.

Check color contrast when a token pair is defined, not when a screen is reviewed.

Text needs 4.5:1, or 3:1 if it’s large, and that includes placeholder text and text shown on hover or focus. Borders, icons and state indicators needed to identify a control need 3:1.

How large should a touch target be?

WCAG 2.2 sets the floor at 24 by 24 CSS pixels, Apple asks for 44 by 44 points and Material for 48 by 48 dp, so a component default of 44 to 48 units per side sits above every published minimum.

StandardMinimum sizeStatusApplies to
WCAG 2.5.8 Target Size (Minimum)24 x 24 CSS pxLevel AA, with a spacing exceptionWeb
WCAG 2.5.5 Target Size (Enhanced)44 x 44 CSS pxLevel AAAWeb
Apple Human Interface Guidelines44 x 44 ptPlatform guidelineiOS apps
Android accessibility guidance (Material Design)48 x 48 dp, about 9 mmPlatform guideline, 8 dp spacing advisedAndroid apps

Why the numbers disagree

They measure different things. WCAG 2.5.8 is a testable floor with a spacing escape, while the platform figures are design recommendations for finger input.

W3C says as much in its Understanding document: meeting the 24 pixel size is the best practice regardless of spacing, and important controls should aim for the stricter SC 2.5.5.

The units differ too. CSS pixels are density-independent, and Google puts 48dp at about 9 mm of physical size whatever the screen.

Teams that ship the same component inside an app should read up on mobile app accessibility, since the Apple and Android figures come from native guidance.

The spacing exception, and where it fails

A row of six 20 by 20 CSS pixel icon buttons passes with a 4 pixel gap and fails with none, according to W3C’s Understanding document for SC 2.5.8.

Stacking breaks it. Two rows of buttons only 16 CSS pixels high, with a 1 pixel gap between rows, fail, and so do dropdown menu items 18 CSS pixels high, while 24 pixel items pass.

The size rule has other exceptions too. A target passes when another control on the same page does the same job at the required size. Inline targets inside a sentence are exempt, and so are user agent controls where the browser default is left untouched. Essential presentation is the last one, meaning a particular presentation is essential or legally required, as with pins on a map.

Building the size into the component

Pad the hit area, not the glyph.

W3C lists min-height and min-width on the target container as a sufficient technique (C42), which lets a 24 pixel icon sit inside a 44 pixel target.

Native platforms do part of this for you. In Android’s Jetpack Compose documentation (as of October 2026), Material components such as Checkbox, RadioButton, Switch and Slider set the 48dp minimum internally, but only when the component can receive user actions.

How do design tokens keep components consistent?

Swap hardcoded colors, spacing, type sizes and radii for named values, and every component reads its look from one shared source. Those named values are design tokens.

Change the value once and every component that references it follows.

Token tiers

Material Design 3 splits tokens into tiers. Reference tokens hold raw values, such as a palette step or a pixel size. System tokens are roles that point at those, primary or surface for instance, and component tokens hold usage values for one component, like a button background, pointing at a system token.

Components should read from the system tier, because swapping what a system token points at changes every component that uses it.

Skip the system tier and each component token points straight at a palette color, which turns a theme change into a search-and-replace.

Naming tokens and building scales

Name tokens for their job, not their value. That means color.text.danger instead of red-600, space.4 instead of 16px, and radius.control instead of radius-8.

Style Dictionary’s category, type and item (CTI) convention lets its transforms apply by token path, so a color token gets color conversions and a size token gets size conversions. Predictable names make that automatic.

Spacing scales follow the same logic: a fixed list of steps, often built on an 8-point grid, so a developer picks a step instead of typing a number. A type scale works the same way.

Dark mode without duplicated components

Dark mode belongs in the system tier. A token like color.surface points at one reference value in the light theme and another in the dark theme, and no component changes.

Test every text and boundary pair in both themes, since a pair that passes in light can fail in dark.

Token formats and tooling

zeroheight’s Design Systems Report 2025 found design tokens in 84% of design systems, up from 56% a year earlier.

The format caught up with that adoption. The W3C Design Tokens Community Group announced the first stable Design Tokens specification (2025.10) on 28 October 2025, with reference implementations in Style Dictionary, Tokens Studio and Terrazzo.

As of that release, the stable version covers theming, multi-file support and modern color spaces such as Display P3 and Oklch.

Style Dictionary reads token files once and builds platform outputs for iOS, Android, CSS and JavaScript. On the design side, keep Figma variables aligned with those same files.

Token systems get harder to manage as they mature. zeroheight’s respondents describe architectures that grow complex and surface problems when new needs arise, so retire tokens nobody references.

When should a variant become a new component?

Add a variant when the component keeps its purpose and only its structure or style adapts to a new context. Create a new component when the purpose itself changes.

That is the rule in a March 2026 Webflow blog post by Alessia Sannazzaro, Managing Director of the agency Code & Wander.

Work through the decision in this order.

  1. Search the existing inventory first. TimelyCare’s Helix rules forbid creating a component before checking it, and Microsoft’s Fluent contributor wiki carried the same advice, though that wiki now points to other docs.
  2. Name the purpose. If the purpose changed, stop: it is a new component.
  3. If the purpose holds and only structure or style adapts, add a variant.
  4. Check the reach. Fluent’s guidance asked for components stripped of product-specific colors and customizations, and Helix calls a localized, very specific component a snowflake that stays outside the system.
  5. Write a proposal for anything shared.
  6. Build design and code together, on feature branches in both the design tool and the code library, then test, document, version and release.

Variant explosion

Variants fail by accumulation, not by one bad decision.

Webflow’s example is a card that starts with one layout, then gains an optional image, a version without an image, a badge and a compact version. Each addition is reasonable on its own, and together they form a web of conditional logic nobody can track.

The post describes the next step in the spiral: teams create new components to avoid friction with the old ones, which adds more noise.

Review variants on a schedule and retire the ones no product uses.

What needs a proposal

At TimelyCare, new or modified components, variants, tokens and patterns all need a proposal. Bug fixes, spec corrections and documentation-only updates don’t.

Helix’s documentation (updated June 2026) also flags changes to component props or token values for human review before merging.

How should UI components be documented and tested?

Document each component as Storybook stories plus a usage page. Testing then splits across interactions and accessibility rules, then visual appearance, then a manual keyboard and screen reader pass.

Each layer catches failures the others cannot see.

Documentation

Chromatic’s documentation describes Storybook as the place to define a component’s states and variations as stories. Those stories double as living documentation and as the fixtures for every test below.

Stories show behavior, but they can’t carry guidance. The usage page does that, and it should cover:

  • when to use the component, and when not to
  • anatomy and a props table
  • the full state set
  • do and don’t examples
  • accessibility notes, including keyboard behavior

zeroheight’s 2025 report found that 68% of teams document their design system in multiple places, with Figma and Storybook the dominant pairing.

Splitting it is how documentation drifts. Link each Figma component to its story, and treat the Figma developer handoff as the moment to confirm the two still match.

Testing layers

LayerWhat it catchesTool
InteractionClicks, typing and keyboard flows that stop producing the expected resultStorybook interaction tests (Vitest, Playwright)
Accessibility rulesWCAG rule violations in the rendered DOMStorybook accessibility addon (axe-core)
Visual regressionPixel changes across states, viewports and browsersChromatic
Manual reviewFocus order, announcements and anything a rule cannot judgeKeyboard and screen reader pass

Storybook 9 ships interaction tests powered by Vitest and Playwright, accessibility tests powered by axe-core, and visual tests powered by Chromatic.

Chromatic renders stories in cloud browsers, compares each snapshot with an accepted baseline, and covers Chrome, Firefox, Safari and Edge.

Automated accessibility checks leave a large share open. Deque’s 2021 study of more than 2,000 audits and 13,000 pages found its axe-based testing caught 57% of issues by volume.

Deque measured its own tooling on its own audit data, so treat 57% as a vendor figure, not a guarantee.

Versioning and deprecation

Version a component library with Semantic Versioning, and declare the public API first: props, slots, events and token names.

Backward-compatible bug fixes go out as patches. Backward-compatible additions, and any deprecation, make a minor release, and incompatible changes to the public API need a major.

The SemVer 2.0.0 specification requires a minor release whenever public API functionality is marked deprecated, so removal can only follow in a later major release. Renaming a prop is therefore two releases, not one.

Write each change into a changelog. zeroheight’s respondents list automated changelogs and release notes among the things they most wish they could automate.

When do UI component best practices stop paying off?

A component with a single use doesn’t need the full treatment, and neither does an interface too dense for large targets. The same goes for a team that can’t staff the upkeep a shared library demands.

One-off components

Build a component in the product first and promote it to the library when a second team asks for it. A library entry written for one screen carries that screen’s assumptions to everyone else.

Stay local when the component is used on a single screen or depends on product-specific data or colors. Promote it once a second team needs it and the purpose is the same in both uses.

Dense interfaces

Some interfaces cannot reach 44 pixel targets. W3C names interactive data visualizations, and online forms that must replicate paper layouts by law, as cases where dense targets can be unavoidable.

Where practical, W3C asks authors to offer equivalent functionality by other means. It also notes that a density control, or an option to enlarge the active area without changing the visible size, can help.

For a data-heavy admin table, decide on purpose: use the spacing exception, test it, and record the exception on the component’s usage page.

Staffing the upkeep

zeroheight’s Design Systems Report 2026 summary puts the share of design system teams without enough people at 61%, with lack of resources the top challenge in the survey.

The 2025 report put the figure at 41% for companies under 500 employees and 54% for those with 500 or more. The two surveys use different samples, so read the change as a direction, not a measured jump.

The 2025 report also found an average dedicated team of 3 people at companies under 100 employees. A full design system with tokens, stories, visual tests and versioning is a product that needs that staffing.

Respondents with low-trust systems describe accessibility and documentation as the first work dropped when resources run short.

For a small team, start with tokens and native elements. Tokens are where zeroheight’s respondents report the most satisfaction.

Add stories, visual tests and formal versioning when a second team consumes the library.

UI Component Best Practices FAQ

What is a UI component?

Reusable interface units that package markup, styling and behavior behind a defined API count as components. Buttons, text fields and dialogs are the usual examples, each with a single job and a fixed set of states.

Is a UI component the same as a UI element or a widget?

No. Anything visible on screen counts as a UI element, plain text and icons included. A component is that element packaged for reuse, with props and states, while “widget” is an older toolkit term that usually means an interactive control.

What is the difference between a design system and a component library?

The component library is the coded set of components. A design system goes wider, adding design tokens, usage guidelines, documentation and the governance rules that decide what enters the library.

A team can ship a library without a design system, but not the reverse.

Which UI components does almost every product need?

Buttons, text inputs, checkboxes, radio buttons, selects, dialogs, tabs, tooltips, alerts, navigation and tables cover most products. Start with these, since they carry the keyboard and focus behavior users expect from every interface.

Should a team build its own components or adopt a library?

Adopt first. Standard controls like menus, dialogs and tabs are costly to build correctly, so build only the pieces that carry your brand or a behavior no library offers.

Adopting also does not lock you into a look, because some libraries ship without styles.

How do Radix UI and Material UI differ?

Radix Primitives are unstyled, open-source React components that follow WAI-ARIA design patterns where possible, so you supply every style. Material UI comes at it the other way: it implements Google’s Material Design in React and ships with default styles and theming.

Choose Radix to build a custom look, and Material UI to start from Material Design.

Where to Start When an Existing Library Falls Short

Retrofitting an existing library goes best in a fixed order. Start with design tokens, meaning color, spacing and type values. Add accessibility and interaction checks to every story next, and only then work through the components themselves, highest-traffic first.

Tokens come first because one change reaches every component, and the most common failure in WebAIM’s 2026 analysis, low-contrast text on 83.9% of home pages, lives in color values. Tests come second so later refactors cannot reintroduce what the first pass fixed.

The cost is review work: a token change shifts every visual baseline at once, so plan a full snapshot review before merging.

A web accessibility checklist turns the second pass into a concrete audit.

Verified 26 October 2026. A library that already routes every color through tokens can skip straight to the test pass.

Bogdan Sandu
Latest posts by Bogdan Sandu (see all)