Picker menu
canonAnchored menu of items with optional check marks and icons.
Slots added 27 Sep 2026 (acrm !3909, wave D): separator rows `{ key, sep: true }` with role=separator (edge/double separators dropped, same rule as Menu button), per-item `ariaLabel` for rows whose visible text is shorter than the full sentence, and a clear row (`clearLabel`/`clearIcon`/`onClear`) — role=menuitem, no check, NOT danger (clearing a value is reversible; red is only for deleting data). No group headings. Registry repaired 17 Oct 2026 (review F6): added exported PickerMenuPanel to react[].
Used in 51 files · 36 areas · 64× — components/AppShell, components/FilterBar, components/ai-employees, components/assistant, components/calendar, components/callwrapup …
@acrm/ui <PickerMenu> <PickerMenuPanel>.acrm-popover .acrm-popover-item .acrm-popover-sep .acrm-popover-emptySourceStoryLegacy card popover.htmlDefault
export const Default = () => {
const [v, setV] = useState('week');
return (
<PickerMenu
items={VIEWS}
value={v}
onPick={setV}
header="Zobrazení"
trigger={(open) => (
<TriggerButton label={VIEWS.find((i) => i.key === v)?.name ?? ''} open={open} />
)}
/>
);
};Variants
plain rows
icon rows (.ic slot, 18px)
stage dot in the icon slot (dot prop)
one line — a long name ends with an ellipsis, full text in title (no grey trailing tag)
grouped rows (sep item — no group heading, DS: menu has no eyebrow)
export const Variants = () => {
const [fn, setFn] = useState('sum');
return (
<div style={row}>
<Labeled label="plain rows">
<StaticPopover width={200}>
<MenuItem checked>Vše</MenuItem>
<MenuItem>Moje</MenuItem>
<MenuItem>Týmu</MenuItem>
</StaticPopover>
</Labeled>
<Labeled label="icon rows (.ic slot, 18px)">
<StaticPopover width={200}>
{VIEWS.map((i) => (
<MenuItem key={i.key} icon={i.icon} checked={i.key === 'week'}>
{i.name}
</MenuItem>
))}
</StaticPopover>
</Labeled>
<Labeled label="stage dot in the icon slot (dot prop)">
<StaticPopover width={200}>
{STAGES.map((s) => (
<MenuItem key={s.key} dot={s.dot} checked={s.key === 'qual'}>
{s.name}
</MenuItem>
))}
</StaticPopover>
</Labeled>
<Labeled label="one line — a long name ends with an ellipsis, full text in title (no grey trailing tag)">
<StaticPopover width={220}>
<MenuItem checked>Tento týden</MenuItem>
<MenuItem>Obchodní případy převzaté od kolegy v zastoupení</MenuItem>
<MenuItem>Archiv</MenuItem>
</StaticPopover>
</Labeled>
<Labeled label="grouped rows (sep item — no group heading, DS: menu has no eyebrow)">
<PickerMenu
items={GROUPED}
value={fn}
onPick={setFn}
trigger={(open) => (
<TriggerButton label={FUNCS.find((i) => i.key === fn)?.name ?? ''} open={open} />
)}
/>
</Labeled>
</div>
);
};States
trigger rest
trigger disabled (menu does not open)
open — selected row carries the accent check (static replica)
row hover (--hover-surface) / danger row (static replica)
clear row (onClear — no radio check, NOT danger: undo is reversible)
export const States = () => {
const [v, setV] = useState('week');
const [fn, setFn] = useState<string | null>('sum');
return (
<div style={grid}>
<div style={row}>
<Labeled label="trigger rest">
<PickerMenu
items={VIEWS}
value={v}
onPick={setV}
trigger={(open) => <TriggerButton label="Týden" open={open} />}
/>
</Labeled>
<Labeled label="trigger disabled (menu does not open)">
<PickerMenu
items={VIEWS}
value={v}
onPick={setV}
disabled
trigger={() => (
<Button disabled>
Týden <Icon name="chevron-down" />
</Button>
)}
/>
</Labeled>
<Labeled label="open — selected row carries the accent check (static replica)">
<StaticPopover width={200}>
<MenuItem icon="calendar">Den</MenuItem>
<MenuItem icon="calendar-week" checked>
Týden
</MenuItem>
<MenuItem icon="calendar">Měsíc</MenuItem>
</StaticPopover>
</Labeled>
<Labeled label="row hover (--hover-surface) / danger row (static replica)">
<StaticPopover width={200}>
<MenuItem icon="pencil" role="menuitem" check={false}>
Upravit
</MenuItem>
<div className="acrm-popover-sep" />
<MenuItem icon="trash" role="menuitem" className="danger" check={false}>
Smazat
</MenuItem>
</StaticPopover>
</Labeled>
<Labeled label="clear row (onClear — no radio check, NOT danger: undo is reversible)">
<PickerMenu
items={FUNCS}
value={fn}
onPick={setFn}
clearLabel="Bez výpočtu"
onClear={() => setFn(null)}
trigger={(open) => (
<TriggerButton
label={FUNCS.find((i) => i.key === fn)?.name ?? 'Bez výpočtu'}
open={open}
/>
)}
/>
</Labeled>
</div>
<Note>
Picking closes the menu and calls onPick only when the key changes. Esc, scrim click, scroll
of an ancestor and resize close it. The trigger render-prop receives `open` for its own
styling; the menu itself carries no heading (DS rule: no eyebrow in menus).
</Note>
</div>
);
};With icon & kbd
icon per row (Tabler name)
stage dot instead of icon — live trigger
export const WithIconAndKbd = () => {
const [v, setV] = useState('offer');
return (
<div style={row}>
<Labeled label="icon per row (Tabler name)">
<StaticPopover width={200}>
<MenuItem icon="user" checked>
Osoba
</MenuItem>
<MenuItem icon="building">Firma</MenuItem>
<MenuItem icon="briefcase">Obchod</MenuItem>
</StaticPopover>
</Labeled>
<Labeled label="stage dot instead of icon — live trigger">
<PickerMenu
items={STAGES}
value={v}
onPick={setV}
trigger={(open) => (
<TriggerButton label={STAGES.find((s) => s.key === v)?.name ?? ''} open={open} />
)}
/>
</Labeled>
</div>
);
};Composition
section title as a switcher — SectionTopBarTitle is the trigger
kebab menu — actions with a separator and a danger row (static replica)
export const Composition = () => {
const [pipe, setPipe] = useState('obecna');
const PIPES = [
{ key: 'obecna', name: 'Obecná pipeline', icon: 'layout-columns' },
{ key: 'tym', name: 'Obchodní tým', icon: 'briefcase' },
];
const cur = PIPES.find((p) => p.key === pipe) ?? PIPES[0]!;
return (
<div style={grid}>
<Labeled label="section title as a switcher — SectionTopBarTitle is the trigger">
<PickerMenu
value={pipe}
onPick={setPipe}
items={PIPES}
trigger={(open) => (
<SectionTopBarTitle name={cur.name} tileIcon={cur.icon} tone="blue" open={open} />
)}
/>
</Labeled>
<Labeled label="kebab menu — actions with a separator and a danger row (static replica)">
<StaticPopover width={220}>
<MenuItem icon="link" role="menuitem" check={false}>
Zkopírovat odkaz
</MenuItem>
<MenuItem icon="users-group" role="menuitem" check={false}>
Sloučit duplicity
</MenuItem>
<div className="acrm-popover-sep" />
<MenuItem icon="trash" role="menuitem" className="danger" check={false}>
Smazat
</MenuItem>
</StaticPopover>
</Labeled>
</div>
);
};