Panes, rails and sheets
Drawers, side rails and dialogs, and how they stack.
Details open in a drawer from the right, below the top bar, so the list stays in view. Confirmations and short forms are centered dialogs. A side rail holds secondary lists on wide screens and moves inline on smaller ones.
The problem
People open an intro from a table, then want to look at the next one. If every detail is a new page, they lose their place in the list; if every detail is a centered popup, there's no room and the list disappears behind it. And when panels open from panels, Escape has to close the right one.
What to do
- Details slide in from the right. A drawer opens below the top bar over a dimmed page, so the list stays in view. Two widths: 576px for one item, 672px for a list.
- Centered is for short decisions. Confirming something is a ConfirmDialog; creating or editing a small record is a Dialog. A whole person or organization gets its own page, not a drawer.
- The top one closes first. Escape or ✕ closes the drawer on top. A drawer opened from a drawer closes before its parent, and layers always stack in the same order.
Which one do I use?
| Situation | Do this | Bridge example |
|---|---|---|
| One row's details (an intro) | Drawer, size="item" (576px) | An intro opened from the intros table |
| A list behind a person or a number | Drawer, size="list" (672px) | A relationship; the contacts you met in one week |
| Something inside a drawer opens more detail | A second drawer on top; Escape closes it first | An intro opened from a relationship drawer |
| Creating or editing a small record | Dialog, centered, up to 512px | Add a network |
| Confirming before removing | ConfirmDialog (Destructive actions) | Stop sharing with Leah Okonkwo? |
| A whole person or organization | Its own page, not a drawer | /network/quillbase.example |
| A secondary list next to a feed | A side rail, 426px on wide screens, collapsible to a 40px handle; below 1024px it sits under the feed | Activity's Recently met rail |
See it work
Live examples built from the package on the sample network. Click through them.
Open one item without leaving the list
Open an intro. The drawer slides in over the page; Escape or ✕ closes it and focus goes back to the row.
- Accepted
Priya Natarajan → Leah Okonkwo
4 days ago
- Requested
Jonas Becker → Hannah Weiss
Yesterday
- No reply yet
Daniel Osei → Tomás Herrera
Sep 1
- Declined
Aleksandr Volkov-Petrenko → Ravi Menon
Aug 28
A drawer from a drawer: the top one closes first
Open the relationship, then one of its intros. Press Escape twice: the intro closes, then the relationship.
A side rail that collapses, then moves under the feed
Collapse the rail to its handle and open it again. Switch to the narrow width: the rail becomes part of the page, below the feed, and can't collapse.
Priya Natarajan → Leah Okonkwo
4 days ago
Mei Lin Zhou → Ravi Menon
Sep 2
Jonas Becker → Hannah Weiss
Yesterday
Fatima Al-Sayed → Isabella Rossi
2 days ago
What to write
| Part | Rule | Example |
|---|---|---|
| Drawer title | The thing itself: the people, the person or the week. | Priya Natarajan → Leah Okonkwo |
| Drawer subtitle | One line: who and when. | Made by you · 4 days ago |
| Close | An ✕ button named "Close" for screen readers. | ✕ (Close) |
| Rail handle | Name the action on the icon button. | Collapse panel · Open panel |
| Rail tabs | Short, sentence case, so the row fits 426px. | New connections · Meetings · Suggestions |
Accessibility
- A drawer is a dialog: its title names it, focus moves inside and stays there, and closing returns focus to the control that opened it.
- Escape closes only the top-most layer: a menu inside a drawer before the drawer, a nested drawer before its parent.
- Layers stack in one order (search and drawers, then profile dialogs, menus and tooltips, confirm and form dialogs, toasts), so a menu or confirmation opened from a drawer is never hidden behind it.
- The collapsed rail keeps a focusable "Open panel" button; while the rail is open, the hidden handle is out of the Tab order.
| Keys | What happens |
|---|---|
| Esc | Closes the top-most drawer or menu. |
| Tab | Moves through the drawer and stays inside it. |
| ← / → | In the week-of-contacts drawer, steps to the previous or next week. |
Components this uses
Each opens that component’s own page, with its options and code.
| Component | Its job here |
|---|---|
| Drawer | The right-hand panel: item for one record, list for a list. Handles focus, Escape and layering. |
| Dialog | Short create and edit forms, centered. |
| ConfirmDialog | Asking before anything is removed or stopped. |
| IconButton | ✕ Close in the drawer header; Collapse panel and Open panel on the rail. |
| DataTable | The list a drawer opens from; it stays in view behind the drawer. |
| Tabs | Switches the rail's views (New connections, Meetings, Suggestions). |
Where Bridge OS differs today
Follow this page, not the gap.
- Every Bridge OS drawer is hand-built with its own animation and close handling.
- The Recently met rail is fixed-position, which breaks the top bar's blur in Safari (see Elevation).
- The rail's tab labels are Title Case in Bridge OS ("New Connections"); they move to sentence case.
Sources
- Approved 2026-11-02; built as packages/ui/src/components/drawer.tsx
- Bridge OS intro-detail-drawer, relationship-detail-drawer, week-contacts-drawer
- Bridge OS
relationship-detail-drawer.tsx - components.md → ConfirmDialog, Toast (overlay ladder)
- Bridge OS
recently-met-rail.tsx - Bridge OS
src/hooks/use-open-org.ts,src/hooks/use-open-profile.ts packages/ui/src/components/dialog.tsx(approved 2026-11-02, Creating records)- Bridge OS
week-contacts-drawer.tsx - Bridge OS
recently-met-rail.tsx,activity-page-content.tsx - Drawer component guidance (handbook);
packages/ui/src/components/drawer.tsx