Anatomy of a React component
My vision for how every React component should look
421
8 min.
The SSB standard defines requirements for the semantics, accessibility, and logic of buttons.
<button> element for actions. <div> and <span> elements with event handlers do not automatically provide button semantics or keyboard behavior.type attribute explicitly on every button. Its value reflects the intended action, not just the button's location:
type="submit" submits the associated form;type="button" performs an interface action without submitting or resetting a form;type="reset" restores the form controls to their initial values.type can cause a form to be submitted: the default behavior depends on the context and the button's form association. A button can be associated with a form through the form attribute even when it is outside the <form> element.type="reset" only when restoring the initial values is the expected action. Resetting a form does not necessarily clear its fields; it restores each control's default value.role="group" with an accessible name for a regular group; use <fieldset> and <legend> for a related set of form controls.role="toolbar" for an actual toolbar, not as a generic replacement for a group. A toolbar implements arrow-key navigation between its controls and the corresponding focus management.aria-pressed="true" or aria-pressed="false". If the label changes, for example from “Play” to “Pause,” aria-pressed is generally not added.aria-label or aria-labelledby.aria-hidden="true". Avoid adding a duplicate name with aria-label unless needed.Enter and Space. Custom event handlers must not break native keyboard activation or trigger the same action twice.:focus-visible to style keyboard focus, and check its contrast and visibility against every background in use.:hover, :active, :focus-visible, and :disabled states must be visually distinguishable where applicable. Hover must not be the only indication of an action: it is unavailable with touch input and does not replace focus or pressed states.disabled attribute for an unavailable button. Unlike aria-disabled="true", it prevents activation and removes the button from the normal focus order.aria-disabled="true" only when an unavailable button needs to remain in the focus order. In that case, the action and its event handler must be blocked separately.disabled while the operation is in progress.aria-busy="true" indicates that the relevant element is being updated, but does not by itself guarantee that loading text will be announced. Expose the status separately, for example with an element using role="status".aria-busy, restore the button to its current state, and make the result or error available to the user.cursor: pointer on enabled buttons and cursor: not-allowed on disabled buttons. The cursor is only a visual cue; it does not replace button semantics or states.1px. The effect must not interfere with text, focus, or other states.prefers-reduced-motion: reduce is active, unless movement is needed to understand a state change.24 × 24 CSS px, or meet one of the criterion's exceptions, such as sufficient spacing between adjacent targets.type. Verify the behavior of buttons inside a form and of buttons associated with a form through the form attribute.:hover, :active, :focus-visible, disabled, and loading states are visually distinguishable and do not rely only on color or the cursor.role="toolbar", also verify arrow-key navigation, focus management, and Tab behavior.Buttons with explicit types:
<form action="/subscribe" method="post">
<button type="submit">Subscribe</button>
<button type="reset">Restore initial values</button>
</form>
<button type="button">Open settings</button>Icon-only button and a group of buttons:
<button type="button" aria-label="Delete">
<svg aria-hidden="true" viewBox="0 0 24 24">...</svg>
</button>
<div role="group" aria-label="Formatting">
<button type="button" aria-pressed="false">Bold</button>
<button type="button" aria-pressed="false">Italic</button>
<button type="button" aria-pressed="false">Underline</button>
</div>Button states and keyboard focus:
button:enabled {
cursor: pointer;
transition: transform 120ms ease;
}
button:disabled {
cursor: not-allowed;
}
button:hover:enabled {
background-color: #e0e0e0;
}
button:active:enabled {
background-color: #d0d0d0;
transform: translateY(1px);
}
button:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
button {
transition: none;
}
}Choose focus-indicator and background colors with the interface's contrast in mind. The :focus-visible pseudo-class follows browser heuristics and may appear for reasons other than keyboard input.
Asynchronous operation with a separate status message:
<div aria-busy="true">
<button type="submit" disabled>Saving...</button>
</div>
<p role="status">Saving your changes</p>aria-busy marks the region being updated, while role="status" communicates the status change without moving focus. When the operation finishes, the region is no longer busy, the button is updated, and the status reports the result.
My vision for how every React component should look
421
8 min.
The SST standard defines requirements for the semantics, accessibility, and logic of tabs
62
7 min.
The SSF-U standard defines requirements for the semantics, accessibility, and logic of fullscreen
248
2 min.
The SSA standard defines requirements for the semantics, accessibility, and logic of accordion
258
2 min.
An Analysis of Critical Web Design Mistakes. Why Sliders, Autoplay, and Slow-Loading Pages Reduce Conversion Rates and Rankings on Google
232
2 min.
The SSP standard defines requirements for the semantics, accessibility, and logic of pagination
240
1 min.