new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Supabase · all subjects

accessibility

15 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Focus management with tabIndex

All interactive page elements should be reachable by keyboard. Add tabIndex={0} to all buttons, links, and non-text inputs, ideally at the component level. Consider tying the state of tabIndex to the disabled state of a component, if applicable.

Keyboard navigation across browsers

Chromium-based browsers and Firefox handle keyboard navigation automatically via the Tab key. Safari by default requires the Option key to also be held down. Enabling Keyboard navigation on macOS Settings removes this requirement but makes links non-tabbable as a result.

Focus ring utility classes

Two shared focus ring utilities are available: focus-ring (for buttons, inputs, and most controls with offset ring) and focus-inset (for dense or flush surfaces such as interactive table rows with inset outline). focus-ring expands to outline-hidden, focus-visible:ring-2, focus-visible:ring-ring, focus-visible:ring-offset-2, and focus-visible:ring-offset-background. focus-inset uses outline instead of ring to paint reliably on interactive table rows.

focus-inset outline specification

focus-inset uses outline (not ring) because Tailwind ring is box-shadow, which browsers often skip on display: table-row, notably Safari. The outline expands to: &:focus-visible { outline-style: solid; outline-width: 2px; outline-offset: -2px; outline-color: var(--ring); border-radius: var(--radius-md); }. Do not put focus-ring or raw ring-* on a table row, and do not add outline-hidden alongside focus-inset.

Focus indicator best practices

Prefer :focus-visible over :focus so click/tap does not show a focus indicator. Never use outline-none or outline-hidden without a ring or outline replacement. Always use the shared color (ring-ring or outline-ring); variants like primary, danger, warning do not change focus colour. Do not animate the focus indicator; avoid transition-all or transition on controls that show one. Prefer focus-ring or focus-inset over copy-pasting the class stack.

Interactive table rows focus handling

On interactive table rows, use focus-inset only. focus-ring will look fine in some browsers and invisible in others. When the focused element is not the thing that should show the ring (for example a wrapping Link with group, or an InputGroup parent using :has()), keep the explicit group-focus-visible:ring-* or has-[…]:focus-visible:ring-* stack.

Interactive table row example with focus and keyboard support

Example of an interactive table row with proper focus management and keyboard event handling: ```tsx <TableRow key={id} className="relative cursor-pointer h-16 focus-inset" onClick={(event) => { if (event.currentTarget !== event.target) return handleBucketNavigation(bucket.id, event) }} onKeyDown={(event) => { if (event.currentTarget !== event.target) return if (event.key === 'Enter' || event.key === ' ') { event.preventDefault() handleBucketNavigation(bucket.id, event) } }} tabIndex={0} > <TableCell>{name}</TableCell> </TableRow> ```

Components with built-in focus and tabIndex

Button has focus, tabIndex, and the shared ring built-in. The same explicit tabIndex default is also baked into Checkbox, Switch, Select Trigger, Toggle, Accordion Trigger, Collapsible Trigger, Dropdown Menu Trigger, Popover Trigger, Dialog Trigger, Sheet Trigger, Alert Dialog Trigger, and the Sidebar Menu and action buttons. Bespoke interactive elements require these props to be added manually.

Keyboard support for new tab navigation

Consider affordances like ctrl and meta key support for opening in a new tab. Anything that you can do with a mouse input should be replicable by keyboard.

Radio group keyboard behavior

Single-select option groups such as input type="radio" should behave as a single control. Only the first item of radio groups should become focused with the Tab key; the next Tab should move focus from the group to the next focusable control. Individual options inside of a group can be reached by arrow keys (↑ ↓ ← →). Space is the canonical key to activate radio options, with Enter being a secondary affordance.

Skip links for keyboard navigation

Apps with persistent header and sidebar chrome should expose a skip link as the first focusable element to help users jump to specific content. Use the shared Skip to Content fragment which owns the component API, usage sample, and target landmark contract.

Image alt attribute guidelines

Images should have their contents described with an alt attribute. Write an objective description of the content rather than its context. For example, 'A tricolor beagle galloping through a grassy field, ears in the air' is correct; 'Our logo' is incorrect and unhelpful.

aria-label for icons and visual elements

Icons and other visual elements that aren't strictly images should use the aria-label attribute. For example: <BucketIcon aria-label="bucket icon" size={16} />

aria-hidden for purely visual elements

Visual elements that are purely visual aids may be removed from the accessibility tree via the aria-hidden attribute. For example: <ChevronRight aria-hidden={true} size={14} />. Never use aria-hidden={true} on focusable elements, since these are critical pieces of functionality.

sr-only for screen reader only text

Some scaffolding elements only make sense visually, in the context of surrounding visual content. These should be titled with sr-only text for screen readers. For example, a table column for actions may use: <TableHead><span className="sr-only">Actions</span></TableHead>

Give your agent this brain