Skip to content

Composites

X · Composites

Complete interaction patterns

Composites assemble components into a whole interaction and may be domain-aware. The static layer owns their geometry, regions and states; data and behavior arrive with the framework binding. The app shell that hosts them is shown first.

App shell

nav + appbar Element page

One grid of five children — brand, utility, nav, app bar and content — sharing a single placement map. It is the only arrangement whose reading order matches DOM order, so focus never jumps back up the page. Row one is the legacy masthead (logo on white, the navy .topMenu hugging the right corner). The nav-toggle button collapses the nav, whose rows have no icons, so the rail leaves the grid and the app bar and content take its column; on mobile it becomes a drawer. AppBar tabs are added dynamically by pages.

The full-screen page is shell.html, styled by css/classic/composites/shell.css. The specimen below is copied from shell.html by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift. The same run copies its shell around every other composite's full-screen page.

Axis Values
.qf-shell[data-nav] expanded · collapsed · open (mobile drawer)
.qf-shell__brand › .qf-shell__logo | .qf-shell__logo-placeholder configurable SVG logo, or the dashed “Add logo here” slot when none is set
.qf-shell__utility › .qf-shell__links · .qf-shell__identity secondary destinations and the one signed-in identity; rows are .qf-nav__item, each with an icon in a .qf-tooltip-host. When the labels no longer fit on one line (a narrow window or zoom), data-compact shows the icons and moves each label into a bottom-end tooltip. At 30rem or less the links fold into a .qf-shell__more (vertical ellipsis) menu, keeping the masthead one row. The identity opens a menu: the signed-in time, Profile, the Dark theme switch (menuitemcheckbox, the menu stays open), and Sign out. The utility strip carries no switches of its own.
.qf-nav__item[aria-current=page] · __badge · __section navigation parts: the rail is SideNavigation (C-50), placed by .qf-shell > .qf-nav
.qf-nav__row › .qf-nav__twisty · .qf-nav__item · .qf-nav__action a row for what the link cannot contain: a group disclosure (.qf-nav__subitems) or a row action such as “new document”. Plain destinations stay a bare .qf-nav__item.
.qf-appbar__tab[aria-selected] · __search · .qf-bell app bar parts
.qf-page-header · .qf-breadcrumbs content header: the title, subtitle and actions, with the path above them as a Breadcrumb (C-49)
Shell (toggle the nav with the menu button)
Skip to content
Mobile coming soon
Please use a desktop width.

OverlaySystem

X-01 Element page #445

Dialogs behave like windows in an operating system. A [data-window-area] is the view area they live in; each dialog.qf-overlay[data-window] inside it drags by its header, snaps to the edges and corners of that area, resizes from eight grips, raises to the front when it is clicked or focused, and minimizes to a dock. js/windows.js writes the geometry; the nine data-snap rects, the grips, the dock and the drop-zone ghost are CSS.

In an app the area is the whole .qf-shell, not its content: windows stack at --qf-z-window, above the nav and the app bar, and snap over them; minimized windows become tabs in a dock along the foot of the screen, at --qf-z-dock, and snapped windows stop above it. Menus, popovers, toasts and the narrow nav drawer stay above both.

The full-screen page is overlay-system.html, inside the app shell. The specimen below is copied from overlay-system.html by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
[data-window-area] flag — the bounding view area windows are positioned inside; the app's .qf-shell
.qf-overlay[data-window] flag — make the dialog an OS-style window (drag · snap · resize · raise)
[data-snap] left · right · top · bottom · top-left · top-right · bottom-left · bottom-right · maximized — absent is floating
[data-state] active (front window) · minimized (docked; wins over active)
[data-window-action] minimize · maximize · close — on a button in .qf-window-controls
[data-ds-open-window] · [data-ds-close-window] opens that window id (non-modal show()) · closes the window it is in
[data-window-title] · [data-window-icon] label and sprite id for the dock chip; default to the window's own title and icon
.qf-overlay__resize[data-edge] n · e · s · w · ne · nw · se · sw — resize grips, injected by js/windows.js
.qf-snap-preview[data-snap] · .qf-dialog-dock drop-zone ghost and the dock of minimized windows
[data-window-minimizable] false — a window that must be answered (a confirmation) does not minimize
qf-window-snap · -minimize · -restore · -close bubbling events on the window, so a framework that renders it can follow its state
--qf-window-dock the dock's height on its area, written by js/windows.js; snap rects stop above it
Windows: drag, snap, resize and dock
Open a window
CS-2041 · Water damage
Status
In review
Adjuster
Jane Doe
Opened
11 Sep 2026
Reserve
$14,200
HO-3 renewal.docx

Endorsement 4 adds water back-up cover to the renewal term. Drag this title bar to an edge to snap the window; drag any border to resize it.

Adjusters on this claim
Owner
Jane Doe
Field
Marcus Webb
Desk
Priya Raman
Edit saved search

The search on screen differs from the saved one. Update saves the name and the search as they are now.

Loss photos (12)

Opened from the toolbar with data-ds-open-window. New windows cascade from the top-left of the area.

Activity

Escape closes the focused window and returns focus to the control that opened it.

Drag the title bar — edge = half · corner = quadrant · top = maximizedDrag any border — eight grips, min 20rem × 10remAlt + Arrow — snap left / right / up / downDouble-click the title bar — toggle maximizedMinimize — tabs dock along the bottomEscape or Close — focus returns to the opener

DataGrid

X-03 Element page #447

Table plus column persistence, a column picker and infinite load. Adds a toolbar, a sticky-header scroll body, the picker popover and the load-more sentinel.

The specimen below is copied from datagrid.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-grid · __body · __sentinel · __drop-indicator regions and reorder feedback
.qf-column-picker List of toggles with drag handles
Grid with column picker (click "Columns")
Approve invoice INV-2026-0412 jdJane Doe Tomorrow High
Index batch Batch #2041 akAlex Kim Today Medium
Review contract MSA-2026 mrMaya Rossi 3 days Low
Assess claim CS-2041 Unassigned Next week High
Archive statements Finance / 2025 tsTom Sato Next month Low
Approve invoice INV-2026-0398 jdJane Doe Next month Medium
Verify identity Person 10442 akAlex Kim Next month Low
Loading more…
Columns

Kanban

X-04 Element page #448

Columns derived from a list-of-values property; cards are compact Cards wrapped in a DragSource. Cross-column drag moves the item and updates the property.

The specimen below is copied from kanban.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-kanban__column[data-state=over] drop target highlight
.qf-kanban__card[data-state] dragging · overlay
__header · __swatch · __count · __cards · __placeholder · __footer parts
Board with a drag in progress
Backlog 4
Archive 2025 statements
Finance
Lowts
Verify identity
Person 10442
Low
Update supplier records
Admin
Mediumak
In progress 2
Approve invoice INV-2026-0412
Acme Holdings
Highjd
Index scanned batch #2041
Scan queue
Mediumak
Review 1
Review contract MSA-2026
Legal
Legalmr
Done 0
Drop cards here

InputFieldMapper

X-05 Element page #449

Dispatches a FieldType to the right control. Visually it adds only the property-type icon in the label; filter mode lays Fields out in a compact wrapping row, and click-to-edit mode uses Field's rest state.

The specimens below are copied from mapper.html, which shows them inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
FieldType String · Date · DateTime · Boolean · Numeric · Currency · User · UserMultiple · Classification · Hierarchy · ListOfValues · LinkedObject · RichText · File …
.qf-field__type-icon · .qf-filter-row label icon / filter-mode layout
One Field per type
jd
Finance › Invoices
CS-2041
Attach
Filter mode

Editor

X-06 Element page #450

Lexical rich-text chrome: a Field-like frame with a formatting Toolbar, a content surface with typographic defaults and a status footer.

The specimen below is copied from editor.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Documents that are not plain rich text open in qf-office, the QEditor host wrapper, as a standalone dialog.qf-overlay[data-window] window rather than in this surface. The editor runs in an iframe (qf-office__embed) and draws its own ribbon, canvas and status bar (office mockups); the window header is its title bar, with the app glyph, the file name and the save state. See DocumentViewer for the full qf-office axis table and OverlaySystem for the window contract (data-window, data-snap, data-ds-open-window).

Axis Values
.qf-editor · __toolbar · __surface · __placeholder · __footer regions
[data-mention] inline mention token
.qf-office[data-kind] · [data-mode] · [data-state] the QEditor host wrapper — documented under DocumentViewer
Rich text

Assessment notes

Visited the property with @Alex Kim on 14 Aug. The kitchen ceiling shows water staining consistent with the tenant's report; see photo set 3.

  • Source: upstairs bathroom, failed seal
  • Estimated repair: £4,250
Recommend approval subject to a second quote.
Editor window · review mode
Assessment report CS-2041.docxDocumentSaving…
Editor window · presentation, maximized in the view area
Claims review Q3 2026.pptxPresentationSaved

DocumentViewer

X-07 Element page #451

Dispatches office files, PDF, image and email to one frame: viewer toolbar, thumbnail rail, canvas and a properties rail. Email swaps the canvas for a header/body/attachments layout.

The specimens below are copied from viewer.html, which shows them inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

qf-office is the host wrapper QAction opens office files in. The QEditor editor runs in an iframe (__embed) and draws its own ribbon, canvas and status bar — the office mockups (X-13 OfficeApp). The window header is the editor's title bar (owner decision Q1): the app glyph and name, the file name, the save state and the window controls. A file therefore opens as a standalone window rather than in place.

The window is an OverlaySystem window: a non-modal dialog.qf-overlay[data-window] driven by js/windows.js — dragged, resized, raised and snapped (data-snap) inside the nearest [data-window-area], which on these pages is the shell's .qf-content. Each file row carries data-ds-open-window="viewer-office-window", so clicking it opens or raises the window. The title bar carries the file name, the kind chip, a save indicator and the standard .qf-window-controls.

Axis Values
.qf-viewer[data-kind] pdf · image · office · email
[data-thumbs] · [data-props] hidden (collapse a rail)
__toolbar · __thumbs · __thumb[aria-current] · __canvas · __sheet · __props · __page regions
.qf-office[data-kind] document · spreadsheet · presentation · pdf — picks the sprite icon and title-bar tint
.qf-office[data-mode] edit · review · view (the editor drops its ribbon panel)
.qf-office[data-state] ready (default) · loading · error
.qf-office__embed · __placeholder · __fallback the editor iframe · boot skeleton · unsupported state with a Download action
__app · __glyph · __title · __filename the title bar in the window header: app glyph and name, the file name button (file flyout)
__brand · __meta · __save[data-state] kind icon, kind chip, saved · saving · unsaved · offline · error
PDF
INVOICE
Acme Holdings · INV-2026-0412 · 14 Aug 2026

Assessment services£3,540.00Travel£710.00Total£4,250.00
TypeInvoice
SupplierAcme Holdings
Amount£4,250.00
StatusApproved
Indexed byjdJane Doe
NotesAdd a note
Email
From
akAlex Kim <alex@example.com>
To
claims@qflow.example
Date
14 Aug 2026, 09:42

Hi team,

Attached are the photos from this morning's visit and the contractor's quote. The leak source is the upstairs bathroom seal.

Alex

photos.zip · 8.2 MBquote.pdf · 120 KB
Editor window · document, floating over the file list
Assessment report CS-2041.docxDocumentSaved
Editor window · spreadsheet, snapped to the right half
Claim ledger Q3.xlsxSpreadsheetSaved
Editor window · booting and unsupported
Q3 review deck.pptxPresentationSaving…
Starting the editor…
Survey scan.pdfPDFSaved
The editor can’t open this file
This PDF uses an encoding the editor cannot render yet. Download it to open it in a desktop reader.

ErrorBoundary

X-08 Element page #452

Three levels wrap an EmptyState[variant=error]. Dialogs get one automatically. Component-level keeps the rest of the page alive.

The specimen below is copied from error-boundary.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-error-boundary[data-level] app · page · component
__details · __stack collapsible technical detail
Component-level fallback

NotificationCenter

X-09 Element page #453

Bell with unread badge; a Popover holding a grouped, sectioned List. The bell in the app shell above opens the same popover.

The specimen below is copied from notifications.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-bell · __badge trigger and unread count
.qf-notifications · .qf-list__item[data-unread] · __time panel parts
Panel
Notifications
  • Today
  • jdJane Doe assigned you a taskApprove invoice INV-2026-0412 · due tomorrow2h
  • Batch #2041 finished indexing14 pages · 0 errors4h
  • Yesterday
  • 3 tasks are overdueIn the Finance queue1d
  • Alex Kim mentioned you"…can @Jane confirm the amount?"1d
Notifications
  • jdJane Doe assigned you a taskApprove invoice INV-2026-04122h
  • Batch #2041 finished indexing14 pages · 0 errors4h

Form

X-10 Element page #454

Form shell: sections with titles, a 12-column row grid, an error summary and a sticky action bar. Field binding and validation come from react-hook-form in the binding.

The specimen below is copied from form.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-form · __section · __section-title · __section-hint · __row · __actions[data-sticky] · __errors regions
[data-span] 3 · 4 · 6 · 8 · (12) columns; collapses to full width on mobile
Customer form with a validation error
CompanyLegal entity details
Enter a valid email address.
Ownership
Required.
Visible to your team only.0 / 500

ObjectDisplay

X-11 Element page #455

Display-definition parsing, tabbed property groups and click-to-edit values. The header shows icon, label, type and actions; each tab is a grid of properties whose values become Fields on click. LabeledObject and LabeledUser chips resolve labels automatically.

Every result resolves to an object. Clicking a result in any view of Search opens this block; only the presentation changes, and data-presentation is the axis that says which. A two-pane view (the Inbox, and Search’s own two-pane view) shows it in place in the right pane, data-presentation="pane", beside the list it was selected from. Every other view — table, cards, list, tree — opens it as an OS-style window: dialog.qf-overlay[data-window] inside the view’s [data-window-area], launched by [data-ds-open-window] and dragged, snapped and docked by the OverlaySystem window layer. In that presentation the window frame carries the object’s icon and title, so the block drops its own and keeps a compact meta strip; the secondary header actions collapse into an overflow menu and the body scrolls on its own inside the frame.

The specimen below is copied from object.html, which shows it inside the app shell, by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-object · __header · __icon · __label · __meta · __actions header
.qf-properties · .qf-property[data-span=full] · __label · __value[data-empty] property grid; hover reveals the edit pencil
.qf-labeled LabeledObject / LabeledUser chip
data-presentation pane — framed, in place, filling the right pane of a two-pane view · window — inside dialog.qf-overlay[data-window], which carries the icon and title instead. Absent: the bare block, laid out by whatever holds it.
__heading · __body · __footer · __overflow title column (label + meta), the scrolling region, a pinned action bar, and the menu button the icon-only header actions collapse into in the window presentation
Object with tabbed properties
Water damage claim
CaseCS-2041·Opened 14 Aug 2026
ClaimantjdJane Doe
StatusIn review
Opened14 Aug 2026
Amount£4,250.00
AssessorUnassigned
Property12 Harbor St, Flat 3
ClassificationClaims › Property › Water
Urgent
DescriptionKitchen ceiling leak reported by tenant on 12 Aug; staining visible, no structural damage observed on first visit.
Opened from a result, as an OS-style window
Every result resolves to an object
A two-pane view shows it in place on the right. Every other view opens it as an OS-style window over the view area.
CS-2041 · Water damage claim
Water damage claim
CaseCS-2041·Opened 14 Aug 2026
ClaimantjdJane Doe
StatusIn review
Opened14 Aug 2026
Amount£4,250.00
AssessorUnassigned
Property12 Harbor St, Flat 3
ClassificationClaims › Property › Water
Urgent
DescriptionKitchen ceiling leak reported by tenant on 12 Aug; staining visible, no structural damage observed on first visit.

Inbox

X-12 Element page

A Search (X-02) with its own treatment: every result set is a canned search, and there is no filter rail. The app bar tabs (Active · Completed · Delegated) are the canned searches. Saved searches reuse the same two panes: a task list on the left and the selected task on the right. Pagination or Load more sits under the list. Saved searches are a menu button in the toolbar; the .qf-saved-views chip row stays in the markup but is hidden.

The right pane has two presentations. Which one shows is a user setting, not a control on the page: Open inbox tasks as in the identity menu, beside the theme, sets .qf-inbox[data-view]. Task view is task-centric. Its header is the task (process, step, status and the object it is on) on a tinted band, with the task’s facts under it: Due, Received, Assigned to, Working user and Last action. The v2 API edits none of those facts, so they are read-only; the header’s buttons are the state changes it does allow, Put on hold and Put back. The body groups the rest into cards: Instructions, the object (its fields and initiating document) and the object’s notes. The footer completes the task with an outcome, the default one filled and one with a note in More, or offers Work task while the task waits in a queue. Object view is how the product works today: the object is the header, then its fields and its activity tabs (Active Task · Documents · Notes · Timeline · Workflow · Related) opened on Active Task, where the task is worked through Instructions, Completion Options, Note and Submit.

Everything a task shows comes from the v2 task (status, dueDate and daysOverUnder, startDate, assigneeId, workingUserId, processName, lastAction, instructions, initiatingDocumentVSId, availableCompleteTaskActions) or from a lookup it names: user and group labels, the object’s label and fields, and the object’s notes, which have a subject and a date but no author. The API has no priority, sender, unread state, step position or delegation, so the Inbox shows none. List rows carry only list data: the task name, process and object type, due state and status.

The Inbox is the two-pane case of the rule that every result resolves to an object: selecting a task in the left list shows that task’s .qf-object[data-presentation="pane"] on the right, and the row it came from carries aria-selected="true" (aria-current="true" is styled the same way, for two-pane views whose list is not a listbox). The right pane is not a bespoke reader: it is the ObjectDisplay block with the Inbox’s own sections composed into its __body. A view that is not two-pane opens the same object as a window instead — see ObjectDisplay.

The full-screen page is inbox.html, inside the app shell and styled by css/classic/composites/inbox.css. The specimens below are copied from inbox.html by bun scripts/design-pages/build-composite-pages.mjs — edit that file, not this one; --check fails when they drift.

Axis Values
.qf-search.qf-inbox two-pane Search: toolbar across the top, task list and footer on the left, detail on the right; no filter rail
__tasks · __task scrolling list pane (.qf-list[data-divided][data-interactive], listbox) and one task row; aria-selected (or aria-current) marks the task whose object the right pane is showing
__due[data-state] overdue · due-soon (none: muted)
__saved · __saved-label · __saved-chevron saved-searches menu button, soft with the search name while one is applied: labelled (icon only below a 36rem toolbar)
[data-view] task · object: which detail pane shows, from the user’s Open inbox tasks as setting ([data-inbox-view] items in the identity menu)
__detail[data-view] the right pane, one per view: .qf-object[data-presentation="pane"] placed in the grid, holding .qf-object__header, __heading, __body and __footer; __eyebrow above the label names what the pane is (Task · process, or the object type)
__facts · __fact Task view: the task’s read-only facts in a band under the header; the header’s own buttons are the state changes (Put on hold · Put back), the footer the outcomes or Work task
__group[data-tone] · __document · __notes Task view: a card in the sunken body (info: the instructions); the initiating-document row inside the object card; the object’s notes, subject and date
__activities · __active-task Object view: the object’s activity tabs, and the Active Task panel (__active-head, __task-name, __ask, __active-actions)
Task view: canned search (Active), a task you are working
Object view: the same task, its object open on the Active Task tab
Task view: saved search (Finance team), a queue task not started, with Load more

Office mockups

X-13 – X-20 All office pages

The QEditor editors as full-screen pages in a maximized qaction window: OfficeApp (X-13), Backstage (X-14), DocumentCanvas (X-15), Workbook (X-16), Deck (X-17), PdfDocument (X-19). Each opens on its own page with a review strip for theme, ribbon mode and width.