Check menu
canonThe one menu for toggling a set of options (columns, tiles, categories): checkbox on the right, optional search, hidden items below a line, reorder by drag or Alt+↑/↓; bottom sheet with Hotovo on a phone.
AD 30 Sep 2026: canon again. The one menu for toggling a set of OPTIONS (column visibility, tile layout, category filter) with optional search, hidden-below-divider and reorder; RecordSelect multi stays the picker of RECORDS. Select has no multiple mode, so the old replacedBy was void. approvedAt after the stories show search, hidden items, keyboard reorder (Alt+↑↓) and the phone sheet. Registry repaired 17 Oct 2026 (review F1): apps/web/src/ds/check-menu.css no longer exists; reorder styling is in ds/reorder.css (step F4). Registry repaired 17 Oct 2026 (review F2): removed classes with no CSS definition and no TSX use on main: .cm-reorder, .cm-dragging, .cm-drop-line, .cm-sheet. Registry repaired 17 Oct 2026 (review F4/F11): attached css reorder.css.
Used in 4 files · 4 areas · 4× — components/activity, components/mail, components/record, components/segment
apps/web <CheckMenu>.acrm-popover .acrm-popover-item .acrm-checkbox .cm-list +3SourceStoryLegacy card popover.htmlLegacy card Inputs.htmlDefault
export const Default = () => (
<div style={{ display: 'grid', gap: 'var(--sp-1)', justifyItems: 'start' }}>
<Chip open label="Kategorie" count={2} />
<StaticPopover width={220}>
<div className="cm-list">
{CATEGORIES.map((c) => (
<CheckItem key={c.key} icon={c.icon} checked={c.checked}>
{c.label}
</CheckItem>
))}
</div>
</StaticPopover>
</div>
);Variants
export const Variants = () => (
<div style={row}>
<Labeled label="plain — a short fixed set, no search">
<StaticPopover width={220}>
<div className="cm-list">
{CATEGORIES.map((c) => (
<CheckItem key={c.key} icon={c.icon} checked={c.checked}>
{c.label}
</CheckItem>
))}
</div>
</StaticPopover>
</Labeled>
<Labeled label="searchPlaceholder + group — search, visible (table order), line, hidden">
<StaticPopover width={260}>
<ColumnList reorder={false} />
</StaticPopover>
</Labeled>
<Labeled label="onReorder — rows are draggable and move with Alt+↑/↓">
<StaticPopover width={260}>
<ColumnList />
</StaticPopover>
</Labeled>
</div>
);States
export const States = () => (
<div style={grid}>
<div style={row}>
<Labeled label="checked / unchecked — checkbox right, menu stays open on toggle">
<StaticPopover width={220}>
<div className="cm-list">
<CheckItem checked>Přehled</CheckItem>
<CheckItem>Aktivita</CheckItem>
<CheckItem checked>Poznámky</CheckItem>
</div>
</StaticPopover>
</Labeled>
<Labeled label="search 'mest' — diacritics-insensitive, both groups filtered, reorder off">
<StaticPopover width={260}>
<ColumnList q="mest" />
</StaticPopover>
</Labeled>
<Labeled label="search with no match — empty state">
<StaticPopover width={260}>
<ColumnList q="xyz" />
</StaticPopover>
</Labeled>
</div>
<div style={row}>
<Labeled label="drag (.cm-reorder) — dragged row dimmed, insertion line">
<StaticPopover width={220}>
<div className="cm-list cm-reorder">
<CheckItem icon="layout-grid" checked draggable>
Přehled
</CheckItem>
<div className="acrm-reorder-line" aria-hidden="true" />
<CheckItem icon="activity" checked draggable>
Aktivita
</CheckItem>
<CheckItem icon="notes" checked draggable dragging>
Poznámky
</CheckItem>
<CheckItem icon="file-text" draggable>
Soubory
</CheckItem>
</div>
</StaticPopover>
</Labeled>
<Labeled label="trigger — rest / open">
<div style={{ display: 'flex', gap: 'var(--sp-3)' }}>
<Chip label="Kategorie" count={2} />
<Chip open label="Kategorie" count={2} />
</div>
</Labeled>
</div>
<Note>
Rows are `menuitemcheckbox`; Enter/Space toggle, ↑/↓ move focus, Esc closes. With `onReorder`
the focused row moves one place with Alt+↑/↓: focus stays on the moved row and a live region
announces the new position („Objem: pozice 2 z 4“). A mouse click right after a drag is
swallowed; a keyboard click is not. Reorder is off while a query is typed. Drag values 1:1
with board.css (opacity 0.45, 3px line).
</Note>
</div>
);Composition
export const Composition = () => (
<div style={grid}>
<div style={row}>
<Labeled label="⚙ layout menu of a record section — visibility + order of tiles (LayoutMenu)">
<div style={{ display: 'grid', gap: 'var(--sp-1)', justifyItems: 'end', width: 320 }}>
<div
style={{
display: 'flex',
alignItems: 'center',
width: '100%',
height: 'var(--row-h)',
padding: '0 var(--sp-4)',
borderBottom: '1px solid var(--border)',
}}
>
<span style={{ flex: 1, font: 'var(--cell)' }}>Přehled</span>
<IconButton icon="settings" aria-label="Skladba karty" aria-expanded />
</div>
<StaticPopover width={220}>
<div className="cm-list cm-reorder">
<CheckItem icon="layout-grid" checked draggable>
Nejbližší akce
</CheckItem>
<CheckItem icon="briefcase" checked draggable>
Obchody
</CheckItem>
<CheckItem icon="tag" draggable>
Štítky
</CheckItem>
</div>
</StaticPopover>
</div>
</Labeled>
<Labeled label="category filter of the activity timeline (CategoryFilterChip)">
<div style={{ display: 'grid', gap: 'var(--sp-1)', justifyItems: 'start' }}>
<Chip open label="Kategorie" count={2} />
<StaticPopover width={220}>
<div className="cm-list">
{CATEGORIES.map((c) => (
<CheckItem key={c.key} icon={c.icon} checked={c.checked}>
{c.label}
</CheckItem>
))}
</div>
</StaticPopover>
</div>
</Labeled>
</div>
<Labeled label="phone (< 720px) — bottom sheet 'Sloupce': grab, title, search, rows, Hotovo; no drag">
<div className="acrm-sheet story-cm-sheet" role="menu" aria-label="Sloupce" style={SHEET}>
<style>{`.story-cm-sheet .acrm-popover-item, .story-cm-sheet .acrm-popover-sep { margin-inline: calc(-1 * var(--sp-3)); width: calc(100% + 2 * var(--sp-3)); }
.story-cm-sheet .acrm-recordselect-search { margin: 0 calc(-1 * var(--sp-4)) var(--sp-1); min-height: calc(var(--sp-7) + var(--sp-1)); }`}</style>
<span
aria-hidden="true"
style={{
display: 'block',
width: 'var(--sp-7)',
height: 'var(--sp-1)',
margin: '0 auto var(--sp-3)',
borderRadius: 'var(--radius-pill)',
background: 'var(--line-200)',
}}
/>
<div style={{ marginBottom: 'var(--sp-2)', font: 'var(--h3)', color: 'var(--ink-900)' }}>
Sloupce
</div>
<ColumnList reorder={false} />
<div style={{ marginTop: 'var(--sp-3)', display: 'grid' }}>
<Button type="button" variant="primary" touch>
Hotovo
</Button>
</div>
</div>
</Labeled>
</div>
);