Components › Overlays & dialogs › Dialog › Drawer form

Drawer form

deprecated
Deprecated — use Form-less dialog (dialog family) — first case: „Nový kontakt", proposal /preview/_navrhy/ramec.html?b=navrh&v=osoba instead. AD 14 September 2026 (OV-2): „drawer form už na nic nepoužíváme, nebudeme používat" — replaced by the form-less dialog. Code on main still has 20 <DrawerForm> call sites in 17 files (Lidé, Firmy, Banka, Majetek, Uživatelé, Zasedačky, Pokladna, Rozpočty, Telefony, Týmy, Vozidla, Dokumenty, Šanony, AI zaměstnanci, provize, náklady) — migration is open work, not done. Existing usages stay until they are migrated; do not build anything new on it.

Deprecated — create/edit forms move to the form-less dialog (e.g. „Nový kontakt"). The side panel with a field form is no longer used for new work.

Used in 18 files · 13 areas · 85× — components/deal, components/mail, components/orders, components/products, components/projects, pages/AiZamestnanciPage …

The create/edit form that slides into the right-hand slot of the app shell. <DrawerForm> gives the panel its head (icon, title, close), a body of <DrawerField> rows and a footer with Zrušit and one primary action; DrawerField is a thin wrapper over Field (packages/ui/src/components/DrawerForm.tsx).

It reuses the Record drawer chrome — .pdr, .pdr-top, .pdr-body, .pdr-foot from apps/web/src/ds/record-drawer.css — and adds no CSS of its own. What it does not reuse is the content grammar (.pdr-rail, .pdr-sec, .pdr-row): those belong to the record preview.

When to use

  • Adding or editing a record from a listing screen (settings lists: users, companies, people, vehicles, bank accounts) where the listing should stay readable next to the form.
  • A form of a handful of fields that belongs to the listing it was opened from.

When not to use

  • A form that needs the whole screen or its own route — that is a page.
  • A task unrelated to the listing behind it — that is a Dialog.
  • Reading a record — that is Record drawer.
  • A question — that is Confirm.

Anatomy

  • Panel .pdr in the shell's drawer slot; no scrim, but the panel carries role="dialog" because it is a form the user is meant to finish.
  • Head .pdr-top: square mark .pdr-top-av.square with the icon, the title .pdr-top-name, and the close control .pdr-ico.
  • Body .pdr-body: grid, gap: var(--sp-4), padding: var(--sp-5), align-content: start; each row is a <DrawerField label hint>.
  • Error: one sentence at the end of the body in --critical-ink (Uložení se nepodařilo. Zkuste to znovu.) — the error prop is a flag, the sentence is fixed.
  • Foot .pdr-foot: Zrušit (.btn.default) and the primary action (.btn.primary) with a check icon; while pending the label reads Ukládám… and the button is off, and it is also off until canSubmit.

Best practices

Do
  • Name the primary action with the verb of the task (Vytvořit, Uložit) and keep it disabled until the form can actually be submitted.
  • Keep every field inside <DrawerField> so labels, hints and errors line up with the rest of the system.
  • Give the head an icon that matches the record kind — it is the only identity the panel has.
  • Close the drawer on success and leave the listing to show the new row.
Don’t
  • Put a second primary action in the footer, or actions in the head.
  • Use it for long, sectioned forms — past roughly eight fields the record deserves a page.
  • Reach for .pdr-sec / .pdr-row inside it; those are the record preview's grammar, not a form layout.
  • Show a spinner over the body — the pending state lives in the button.

Content

  • Title = what is being created, sentence case: Nový kontakt, Nové vozidlo.
  • Field labels are nouns; hints under the field say the format or the consequence (Použije se pro odesílání nabídek.).
  • Primary action = verb. Zrušit is the standard secondary label.
  • record-drawer — the same chrome around a record preview.
  • dialog — when the task does not belong to the listing behind it.
  • text-field, select, choice — the fields that go inside.
  • Stories: components--drawer-form--default, --variants, --states, --composition; legacy overview components--drawer-form-app-only-.

Source: docs/dialog/drawer-form.usage.md · GitLab