Basic Dropdown
A menu button with the full keyboard model - arrows, Home/End, Escape, focus restore.
6 个框架中级
A grid of colour swatches as a listbox, navigated with two-dimensional arrows.
<!--
Picking a colour is choosing a VALUE, so this is a role="listbox" of
role="option", not a menu - aria-selected marks the current one and Enter/Space
commit it. Arrows move in two dimensions across the grid. The swatch background
is the one place a raw colour value belongs: here the colour IS the data.
-->
<div class="relative inline-block">
<button type="button" aria-haspopup="listbox" aria-expanded="true" aria-controls="sw-list" class="inline-flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-semibold text-gray-700 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:focus-visible:ring-blue-400 dark:focus-visible:ring-offset-gray-900">
<span aria-hidden="true" class="h-4 w-4 flex-none rounded-full ring-1 ring-inset ring-black/10" style="background-color:#3b82f6"></span>
Blue
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="m6 9 6 6 6-6" /></svg>
</button>
<div id="sw-list" role="listbox" aria-label="Colour" class="absolute left-0 top-[calc(100%+0.375rem)] z-20 grid max-w-[calc(100vw-2rem)] grid-cols-5 gap-1.5 rounded-xl border border-gray-200 bg-white p-2 shadow-lg dark:border-gray-700 dark:bg-gray-900">
<button type="button" role="option" aria-selected="false" aria-label="Red" tabindex="-1" class="flex h-9 w-9 items-center justify-center rounded-lg ring-1 ring-inset ring-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:ring-white/10 dark:focus-visible:ring-blue-400" style="background-color:#ef4444"></button>
<button type="button" role="option" aria-selected="false" aria-label="Green" tabindex="-1" class="flex h-9 w-9 items-center justify-center rounded-lg ring-1 ring-inset ring-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:ring-white/10 dark:focus-visible:ring-blue-400" style="background-color:#22c55e"></button>
<button type="button" role="option" aria-selected="true" aria-label="Blue" tabindex="0" class="flex h-9 w-9 items-center justify-center rounded-lg ring-2 ring-blue-600 ring-offset-2 ring-offset-white focus-visible:outline-none dark:ring-blue-400 dark:ring-offset-gray-900" style="background-color:#3b82f6">
<svg class="h-4 w-4 text-white drop-shadow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>
</button>
<button type="button" role="option" aria-selected="false" aria-label="Violet" tabindex="-1" class="flex h-9 w-9 items-center justify-center rounded-lg ring-1 ring-inset ring-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:ring-white/10 dark:focus-visible:ring-blue-400" style="background-color:#8b5cf6"></button>
<button type="button" role="option" aria-selected="false" aria-label="Pink" tabindex="-1" class="flex h-9 w-9 items-center justify-center rounded-lg ring-1 ring-inset ring-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:ring-white/10 dark:focus-visible:ring-blue-400" style="background-color:#ec4899"></button>
</div>
</div>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
label必填 | string | - | 加载时朗读的无障碍标签。 |
colors必填 | Swatch[] | - | 要渲染的项目数组。 |
value必填 | string | - | 指标的当前值,需预先格式化。 |
onChange | (value: string) => void | - | On change |
Picking a colour is choosing a VALUE, so this is a `role="listbox"` of `role="option"` with `aria-selected`, not a menu - and Enter or Space commit the highlighted swatch. Arrows move in two dimensions across the grid: Left/Right by one, Up/Down by a full row, clamped at the edges. Each option is `aria-label`-led by its colour name so the choice is announced as "Blue", not by hex. The swatch background is the single place a raw colour value is allowed - here the colour literally IS the data.