Design Principle
Component quality is not the default-state screenshot. Every reachable state must remain understandable, recoverable, and testable across mouse, keyboard, touch, screen readers, loading, errors, and permission limits.
Large Theory
The real complexity of design-system components lives in state combinations. Buttons, inputs, menus, dialogs, table rows, and empty states have more than default and hover. They need enabled, hover, active, focus-visible, disabled, read-only, loading, selected, expanded, empty, error, warning, success, destructive, skeleton, reduced-motion, and forced-colors states expressed as a clear contract. Without a state matrix, agents tend to ship attractive defaults and miss the edges.
Small Points
- Write the state list before visuals: state name, trigger, whether it can receive focus, whether it can be clicked, whether it needs a live region, and whether it preserves layout size.
- Disabled, read-only, and loading are different. Disabled is not operable, read-only can be reviewed but not edited, and loading may block duplicate submission while explaining progress.
- Focus-visible needs a real outline or border, not only shadow. Icon buttons need accessible names.
- Error, warning, and success cannot rely only on color; use text, icon, border, aria-describedby, or status message.
- Selected, expanded, current, and pressed should map to correct semantics such as
aria-selected,aria-expanded,aria-current, andaria-pressed, not only class names. - Skeleton, empty, loading, error, and retry states need fixed dimensions to avoid layout shift when data arrives.
Design Judgment
A component is ready for the library when its matrix answers how each state is entered and exited, whether users can operate it, what screen readers hear, what visual tokens apply, and how it is tested. A component with only default and hover is still a visual fragment, not a callable skill asset.
Implementation Notes
For each component, output a state matrix with state, trigger, visual tokens, DOM/ARIA, keyboard behavior, pointer behavior, copy, layout stability, recovery action, and test assertion. Prefer data attributes or explicit props such as data-state="open", aria-busy, disabled, and aria-invalid. Test at least default, keyboard focus, disabled, loading, error, mobile, and reduced-motion/forced-colors critical branches.
Counterexamples/Risks
A loading button that is disabled but has no progress copy, a form error shown only as a red border, a menu with hover styling but no keyboard focus styling, a dialog skeleton that changes height after data loads, a selected tab shown only through color, and destructive actions sharing an ordinary button variant.
Case Study
Carbon Button and Text Input guidance foregrounds component states, focus, and distinctions such as error, warning, disabled, and read-only. Material Design 3 states notes that disabled components cannot be focused, dragged, or pressed. Radix Primitives stabilizes complex component states through behavior, ARIA, and focus management. NN/g also emphasizes distinguishing button states such as enabled, disabled, hovered, focused, and pressed. The reusable lesson is that state is not a visual appendix; it is the shared contract between component API, accessibility, and QA.
Source Links
Carbon Button: https://carbondesignsystem.com/components/button/usage/ Carbon Text Input: https://carbondesignsystem.com/components/text-input/usage/ Carbon Disabled States: https://carbondesignsystem.com/patterns/disabled-states/ Material Design States: https://m3.material.io/foundations/interaction/states/applying-states Radix Accessibility: https://www.radix-ui.com/primitives/docs/overview/accessibility NN/g Button States: https://www.nngroup.com/articles/button-states-communicate-interaction/
Agent Directive
Before generating components, output the state matrix and test assertions; after the default state, immediately cover hover, focus-visible, disabled, loading, error, empty, selected, reduced-motion, and forced-colors branches.