FilterDropdown
ui filteroverlay
Einheitlicher Filter-Trigger (Label + optionaler „· N"-Zähler + Chevron), der ein DropdownMenu-Popover öffnet. Markiert sich aktiv, sobald etwas gewählt ist. Inhalt bestimmt Single- vs. Multi-Select.
Abhängigkeiten
Barrierefreiheit
- Trigger mit aria-haspopup="menu" und aria-expanded; aktiver Zustand via data-active.
Beispiele
Sortierung
<FilterDropdown ariaLabel="Sortierung" label="Titel (A–Z)" active>
<DropdownMenuItem onSelect={() => sort('az')}>Titel (A–Z)</DropdownMenuItem>
<DropdownMenuItem onSelect={() => sort('za')}>Titel (Z–A)</DropdownMenuItem>
</FilterDropdown> Genutzte Tokens · 11
--accent--bg--border--control-height--ease-standard--fg--field-radius--focus-ring--motion-fast--muted--space-2
Quelldateien
components/ui/FilterDropdown.tsx tsx
import { type ReactNode } from 'react';
import { DropdownMenu } from './DropdownMenu';
import { ChevronDownIcon } from './Icon';
import styles from './FilterDropdown.module.css';
interface FilterDropdownProps {
ariaLabel: string;
/** Triggertext, z. B. „Buch" oder die aktive Sortierung „Titel (A–Z)". */
label: string;
/** Anzahl gewählter Optionen — als Suffix „ · N" am Trigger; 0 = kein Suffix. */
count?: number;
/** Trigger optisch als aktiv markieren (z. B. Sortierung ≠ Default). */
active?: boolean;
align?: 'left' | 'right';
/** Inhalt des Popovers (Checkbox-Liste oder DropdownMenuItems). */
children: ReactNode;
}
/** Einheitlicher Dropdown-Trigger (Label + optionaler Anzahl-Suffix + Chevron),
* der ein Popover öffnet. Kapselt das `DropdownMenu`-Verhalten (Klick-außerhalb,
* Escape) für die Filterleiste. Single- wie Multi-Select bestimmt der Inhalt. */
export function FilterDropdown({
ariaLabel,
label,
count = 0,
active = false,
align = 'left',
children,
}: FilterDropdownProps) {
return (
<DropdownMenu
ariaLabel={ariaLabel}
align={align}
trigger={({ open, toggle }) => (
<button
type="button"
className={styles.trigger}
aria-haspopup="menu"
aria-expanded={open}
onClick={toggle}
data-active={active || count > 0 || undefined}
>
<span className={styles.label}>
{label}
{count > 0 ? ` · ${count}` : ''}
</span>
<ChevronDownIcon size={14} />
</button>
)}
>
{children}
</DropdownMenu>
);
}
components/ui/FilterDropdown.module.css css
.trigger {
display: inline-flex;
align-items: center;
gap: var(--space-2);
height: var(--control-height);
padding: 0 8px;
border: 1px solid var(--border);
background: var(--bg);
border-radius: var(--field-radius);
color: var(--muted);
cursor: pointer;
box-sizing: border-box;
width: 100%;
transition: background-color var(--motion-fast) var(--ease-standard),
color var(--motion-fast) var(--ease-standard),
border-color var(--motion-fast) var(--ease-standard);
}
.trigger:hover {
color: var(--fg);
}
.trigger:focus-visible {
outline: none;
box-shadow: var(--focus-ring);
}
.trigger[data-active] {
color: var(--fg);
border-color: var(--accent);
}
.label {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left;
}
.trigger svg {
flex-shrink: 0;
}
Holen
# MCP (Claude Code / Cursor)
get_component({ name: "filter-dropdown" })
# Registry direkt
https://www.ekklesi.tools/design/registry/components/filter-dropdown.json