Settings page
The grouped settings menu, shipped acrm !4018 (feat(nastaveni): seskupení podle Attio, merged 83d87bb24). Every item of the settings menu is its own page, not a tab: SectionTopBar (identity = the menu item's own icon) plus one centred content column. apps/web/src/pages/settings/SettingsLayout.tsx + settings-nav.ts (single source of truth for structure and RBAC); classes .set-shell, .set-rail, .set-nav, .scol, .set-stack, .table-wrap in apps/web/src/ds/settings.css.
Pattern source: Attio / Linear (Mobbin), owner-approved 27 September 2026.
When to use
- The application's own Settings area (
/nastaveni) — personal preferences, company configuration, templates, AI controls, data schemas, reports. - Any future full settings-style menu that needs the same shape: grouped left rail, one page per item, no tabs.
When not to use
- As a tab inside a record detail. Personal preferences and settings are not a tab of anything — they live in this menu, not under
record-tabs. - For a simple two-way toggle inside one page (Moje | Firemní) — that is a
Segmented controlinside the page's own content, not a second menu.
Anatomy
- Left rail
.set-rail(--sidebar-w): back button + "Nastavení" title, search, then groups.set-groupwith a muted.set-grplabel and.set-itemrows (icon + label). A group with no visible item (RBAC-filtered to zero) renders nothing —SettingsLayoutskips it, it does not show an empty header. - Groups (
SETTINGS_NAV, 30 items): Osobní (Personal) · Firma (Company) · Šablony (Templates) · AI a automatizace (AI & automation) · Data · Přehledy (Reports). - Right column:
SectionTopBarwith the active item's own icon and name as identity (no breadcrumb — "Nastavení › Firma › …" does not exist), section actions on the right viaprimaryAction/SettingsPageActionportal, then.sbody→.scol(660px,margin-inline: auto). - Wide content: a table wider than 660px gets its own horizontal scroller (
.scol .table-wrap { overflow-x: auto }); the page itself never scrolls sideways. - Merged pages: an item that folds together what used to be several tabs stacks its existing
SectionBlocks top-to-bottom in.set-stack(e.g. Připojení = e-mail/calendar block + AI connection block; Schůzky = recording + reminders; Přístup = domains + vendor access). Content itself is recycled 1:1, not rebuilt. - Canvas sections (Uživatelé, Týmy, AI zaměstnanci, Import, Koš, Aktivita) keep their own chrome (own header, own scroll) and take the full right column with no settings breadcrumb bar, to avoid a double header.
- Phone (≤720px): two-step, same shape as the ⌘K palette.
/nastavenialone shows only the full-width menu;/nastaveni/<sekce>shows only that section, with a quiet back arrow (IconButton icon="arrow-left") as the first item of itsSectionTopBar.
Best practices
Do
- Give each settings item exactly one page and one place in the menu — never split one concept across two menu entries, never duplicate a page under two keys.
- Reuse the exact same DS Icon name in the rail item that the same concept already uses in the main app navigation (one icon = one meaning, RULES §8) — never invent a second icon for the same thing.
- Redirect an old URL through
MOVED_SECTIONSwhen a section is renamed or merged, so a bookmark, a doc link or a link the assistant sent still lands somewhere real. - Keep content in
.scolat 660px and centred; widen only the scroll container of a table (.table-wrap), never the page.
Don't
- A TabStrip / Tabs row inside a settings page as a second level of navigation — that is a new menu item (its own page), or at most one
Segmented controlinside the page's own content. - A breadcrumb in the settings
SectionTopBaridentity (Section top bar forbids breadcrumb identity, RULES §8). - A context rail next to settings content — the settings page has no record rail.
- Explanatory body text as a substitute for clear labels (
ds-no-explanatory-textrule) — one known debt still breaks this (Firma › Obecné) and is not the pattern to copy.
Content
- Group labels and item labels are sentence case, translated via
settings:groups.<key>/settings:nav.<key>(i18n, cs+en parity) — never hardcoded strings in the component. - The page identity name is the same string as its rail item's label, read from the same translation key (
activeIteminSettingsLayout.tsx).
Known debts (not the pattern to copy)
- Company e-mail templates have an inline editor; personal templates are a plain list — same
mail_templatestable, split only byscope. - Minutes templates (
sablony-zapisu) have no UI CRUD — create/edit/delete is agent-only via MCP; the page is read-only list + "Vyzkoušet". - Firma › Obecné still carries explanatory body text.
Related
section-top-bar,title-with-entity-tile— the bar and identity every settings page uses.tab-strip,record-tabs— what a settings page explicitly does NOT stack under its bar.section-block— the unit merged pages stack in.set-stack.sidebar-nav-item— the app's own left navigation; the settings rail is a separate, app-local grouped nav (DS has no exported grouped-nav component for it).
Saving, anatomy and irreversible actions (acrm !4323, verified on dev 1. 10. 2026)
- Saving: switches and selects save immediately with a short toast. A block with several fields (Profil, company forms, strategy) ends with
Zrušit · Uložitat the end of the block, right-aligned, both disabled until something changes; Zrušit restores the saved values. Never a lone „Uložit změny“ in the middle of the page and never a Save button per row. - Anatomy: one setting = one row, label left, control right, rows separated by a line (Schůzky: recording, reminder lead time, e-mail reminder). Forms with several related fields stay a stack of fields.
- Irreversible page-level actions (Odhlásit všude jinde, Obnovit odkaz ICS) are the LAST section „Nevratné akce“: row with the label left and a danger button right, always with Confirm (question in the title, consequence in the body, the verb on the button). Actions on a specific object (disconnect an account, delete a row) stay with the object.
- No explanatory grey text under fields (e.g. „E-mail spravuje přihlášení…“ removed — the read-only field says it). Step-by-step connector guides on Připojení stay, they are setup steps, not UI explanation.
- Theme: the stored dark theme applies from app start, also for Settings opened directly by URL and for the loading screen (no white flash).
Source: docs/section-top-bar/settings-page.usage.md · GitLab