Skip to main content

What Views govern

A view is a full page: which regions it has, what fills each, and what the page is expected to do for someone arriving at it. It is the first decision, and it constrains every decision below it — a component chosen without knowing its region is chosen without knowing its constraints. Every Titan page is built from one page frame. This page documents the frame. The archetypes below describe what fills it for a particular kind of page.

The page frame

Regions, in the order they appear:
Header is two slots, not one. Left carries what the page is; Right carries what you can do to it. That split is the frame’s central decision — it is why a page-level action never sits next to the title, and why a status chip never sits with the buttons. The header has a second row, and it holds one thing. A page whose body has sections carries its tab bar there; a page that is filtered rather than sectioned carries its filters there instead. Whichever occupies it, that row’s own underline becomes the header’s bottom edge. One row, two candidates, so they compete. The design library’s Header has a single Type property — Default, Tabs, or Filters — so a tabbed page cannot also put filters in its header and has to put them in the body instead, which is what the table page template does.

Region vocabulary

The frame’s terms, and the words it is not using. These are the names to say in a review.
“Header” is the page header, not the site header. The application chrome around it is a different thing that the frame does not own and this documentation does not cover. A page has exactly one Header; the chrome is outside it.The design library’s page template draws that chrome as two regions — a site header carrying the logo, the account selector, global search and the account menu, and a left nav rail of labelled icons. Both are deliberately out of scope here.
Controls and Actions are easy to confuse. Actions acts on the page — save, publish, delete. Controls changes what the body shows — filter, sort, switch view. An action changes data; a control changes your view of it.

What fills each region

Header — Left

Header — Right

Header — Tab bar

A tab bar divides the page’s body into sections of the same subject, and it belongs to the header rather than sitting between the header and the body. Its presence depends on the shape of the body rather than the shape of the page: a page either has sections or it does not. The header’s second row has three states, and they are exclusive: A tabbed header does not also carry a PageDivider. The bar’s underline is the header’s lower edge, so pass hidePageDivider and let it close the region. Each tab is addressable — selecting one changes the URL, so a section can be linked, reloaded, and reached with the back button (TITAN-VIEW-14). A tab switches which section you are looking at; a control narrows what that section shows; an action changes the subject. Those are three regions, and a tab that filters or saves is in the wrong one.
The composition above is a workaroundHeader cannot hold the bar today, so Tabs renders as a sibling instead of a child. See Open issues for what that costs. At the component level, see Tabs for the bar’s own behaviour — the states a tab carries, the id pairing the shipped TabPanel gets wrong (TITAN-DIV-14, TITAN-DIV-15), what “tab bar” and “tab” name on each side, and the vertical orientation, which is a navigation rail rather than a tab bar (TITAN-GAP-29).

Controls

Contents

The footer has two slots, and which you use depends on whether the page is a step in a sequence or a single unit of work.
The leading slot is for moving backward through a sequence, and nothing else. Not a secondary action, not a destructive one, not help. Its position carries the meaning: left is where you came from. Putting anything else there costs you that.
The leading slot is a convention, not a prop. It is produced by setting justifyContent: "space-between" and wrapping the trailing buttons so they group as one child. The footer does not have a named slot for it, which means nothing enforces “one backward action, tertiary, leftmost” — see TITAN-GAP-25.
Wrapping the trailing group costs you the footer’s gap. The footer spaces its direct children using spacing-3. Once the trailing buttons are wrapped to make space-between work, that gap no longer applies between them, and the group has to supply its own. The published example uses a margin on a button to do it — which is exactly what TITAN-VIEW-08 says not to do.Use a Stack with a spacing-* token for the trailing group rather than a bare wrapper with margins.
A left-aligned footer also exists — every action pushed left, via justifyContent: "flex-start". When to use it is undecided — see Open issues.

What a page view is expected to do

The frame is structure. These are the expectations that make a page feel like a Titan page, and they hold across every archetype.

Accessibility

The view tier owns the page-level accessibility decisions, and it is the only tier that can. A component cannot know it is the only main; a pattern cannot know the heading outline. Landmarks. Each region should map to a landmark role so a screen-reader user can jump between them: The frame does not currently supply these (known issue) — set the landmark yourself on the region wrapper until it does. Heading outline. Title renders the page’s h1. One per page, and the body’s headings descend from it without skipping. Visual size and heading level are chosen independently. A tab label is not a heading — the section it reveals still needs one, because a screen-reader user outlining the page sees tab labels only if they are in the tab bar’s own semantics. The tab bar needs a name and a wired pair. Give Tabs an aria-label describing what it divides — “Campaign sections”, not “Tabs”. Then each tab needs an id and an aria-controls pointing at its panel, and each panel an aria-labelledby pointing back. The frame does not do this for you and the shipped panel guesses wrong (TITAN-DIV-14). Focus order. Region order in the DOM matches visual order: header row, tab bar, controls, body, footer. Provide a skip link to Contents when the header and site chrome together exceed a few tab stops. A tab bar is one tab stop, not one per tab — arrow keys move between tabs, so a bar of nine sections does not cost nine stops on the way to the body. Sticky regions must not obscure a focused element (WCAG 2.2 Focus Not Obscured, AA). Both Header and Footer can be sticky, and both can cover a focused control in a long body. See TITAN-GAP-09. Reflow. The frame works at 320px equivalent without two-dimensional scrolling — a desktop page at 400% zoom, not a phone.

Constraints

Known issues

Views overview: open issues

Divergences, open decisions, and undocumented gaps for Views overview.

The archetypes

Each describes what fills the frame for one kind of page. All seven now have their frame composition written, as first-pass proposals — see each archetype’s own Warning banner for its standing, and Foundations: open decisions for what’s genuinely undecided within them.

List view

A collection you scan, filter, and act on.

Detail view

One record, its attributes, and its related data.

Settings view

Configuration grouped into sections.

Dashboard

Multiple summaries read at a glance.

Wizard

A sequence with a defined beginning and end.

Split view

A list and a detail pane side by side.

Full-page form

A single unit of work, committed once.
  • Button — what fills Actions and Footer
  • Tabs — the bar itself: variants, states, and the vertical orientation
  • SideNav — the neighbouring question the vertical orientation raises
  • Layout & grid — breakpoints, and what the frame does not decide
  • Space — the scale region spacing should come from
  • Elevation — the stacking ladder sticky regions use

Why it works this way

The frame is a vocabulary, not a layout engine. Left and Right do very little — a width ceiling, an alignment. Their value is that two people building two pages reach for the same two words and get the same structure. A more opinionated frame would be easier to use once and harder to use for the twentieth page. The tab bar belongs to the header, not to the body. The design library makes this a property of the header itself — one Type property, whose values are a plain header row, a header with a tab bar, or a header with filters. A bar placed between two regions instead has to be re-justified on every page, and a reader who learned the arrangement in one place has to relearn it in the next. The cost of putting it in the header is that a page with sections and a page without differ in one visible way, the header’s rule, and that is smaller than the bar moving. Two header slots rather than a row of components. The alternative is a header that accepts children and lets each page arrange them. That produces pages where the title is sometimes left of the actions and sometimes above them, and no reviewer can say which is right. Naming the slots makes the arrangement a system decision instead of a per-page one.

List view

A page whose body is one table of objects of the same kind, scanned and acted on.

Detail view

One record, its attributes, and its related data.

Settings view

Configuration grouped into independent sections, on one scrollable page — each section committed on its own.

Wizard

A sequence of dependent steps with a defined beginning and end, one commit at the last step.

Dashboard

Multiple summaries read at a glance — the shape of something, not an enumeration of its members.

Split view

A list and a detail pane side by side.

Full page form

A page whose entire body is one form: several independent sections, one commit, no sequence.
Last modified on September 3, 2026