Basic Input
A labelled text input with helper text wired to it via aria-describedby.
6 frameworksBeginner
A selectable card whose entire surface is the target - and which is still a real checkbox underneath.
<!--
The whole card is the target, and it is still a real checkbox: the card IS the
<label>, and the input inside it is visually hidden - clipped, not
`display: none`, which would drop it from the tab order. Keyboard, form
submission and the screen-reader announcement all come from the input for free.
The checked state is not carried by the blue tint: the box on the left fills in
and shows a checkmark, so it survives greyscale and colour blindness.
-->
<label class="choice-card" for="addon-analytics">
<input
class="choice-card__input"
type="checkbox"
id="addon-analytics"
name="addons"
value="analytics"
checked
/>
<span class="choice-card__box" aria-hidden="true">
<svg class="choice-card__tick" viewBox="0 0 20 20" fill="currentColor" focusable="false">
<path d="M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L3.3 9.7a1 1 0 1 1 1.4-1.4l3.8 3.8 6.8-6.8a1 1 0 0 1 1.4 0Z" />
</svg>
</span>
<span class="choice-card__body">
<span class="choice-card__title">Advanced analytics</span>
<span class="choice-card__desc">Funnels, retention and cohort reports.</span>
</span>
</label>| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Content rendered inside the component. |
disabled | boolean | false | Prevents interaction and dims the control. |
className | string | - | Additional classes merged onto the root element. |
The input is `sr-only`, not `hidden`: clipping keeps it in the tab order and in the accessibility tree, which is the only reason the card is keyboard-operable and posts with the form. Everything visual hangs off `has-[:checked]:` on the card and `peer-checked:` on the tick box - no state, no handler, no `useState`. Swap `blue-50`/`blue-950` for your brand tint, but keep the tick: the tint alone is a colour-only signal and fails 1.4.1.