A compact list of links that jump to sections within the current page — the "On this page" sidebar or in-content table of contents. Each entry is a genuine anchor targeting an element id, so the URL hash updates, the back button works, and the links are operable without JavaScript. Pair section ids in the page with link ids here.
Readiness
complete
Preview
live
Props
3
Examples
2
Code
implementation mapped
When to use
Long documents / settings pages with named sections
An 'On this page' sidebar next to scrollable content
Reference views where users skim to a known section
When not to use
Navigating between separate pages — use real router links
Switching mutually-exclusive panels — use Tabs / VerticalTabs
A hierarchical ancestor trail — use Breadcrumb
Accessibility
Role: navigation
Enter — Jump to the linked section (native anchor behaviour)
Tab — Move between section links
Screen reader: Rendered as a nav landmark with an accessible label (default "On this page") so SR users can locate and skip it. Entries are a real list of links, announced with their section labels.
Notes: Give the nav a meaningful aria_label when more than one navigation landmark exists on the page so they are distinguishable.
Props
Name
Type
Default
Description
links
array
—
The jump targets.
aria_label
string
On this page
Accessible label for the navigation region.
heading
string
—
Optional visible heading rendered above the list.
Examples
On this page
Table of contents for a long settings page.
YAML
type: anchor-jump
props:
heading: On this page
aria_label: On this page
links:
- id: overview
label: Overview
- id: members
label: Members
- id: billing
label: Billing
- id: danger-zone
label: Danger zone
A single, consistent "go back / go up a level" link. Use it at the top of a detail view, a wizard step, or a drilled-in panel to return to the parent context. It renders an `<a href>` so the destination is a real URL — never a JavaScript-only handler — which keeps browser history, middle-click, and screen-reader link semantics intact.
Readiness
complete
Preview
live
Props
2
Examples
2
Code
implementation mapped
When to use
Top of a detail/edit view that was drilled into from a list
A wizard or multi-step flow to step back one level
Returning from a nested panel to its parent surface
When not to use
Closing a modal or dialog — use CloseButton
A full breadcrumb trail of ancestors — use Breadcrumb
An in-page primary action — use Button
Accessibility
Role: link
Enter — Activate the link (native anchor behaviour)
Screen reader: Announced as a link with the visible label text. The arrow glyph is aria-hidden so screen readers read only the destination label (e.g. "Back to library"), not a stray arrow character.
Notes: Always give a destination-bearing label ("Back to library") rather than a bare "Back" so the link target is clear out of context.
The canonical brand treatment for app chrome: render the real Triform logotype from the shared branding assets, then pair it with a short surface label such as Docs, Console, or Admin. It keeps generated shells from inventing text-only headers or local logo variants.
Readiness
complete
Preview
live
Props
3
Examples
1
Code
implementation mapped
When to use
WorkspaceShell or PanelShell headers that identify a Triform-owned surface
Generated documentation and internal tools that need first-viewport brand identity
Compact top-left chrome where the logo and current product label should travel together
When not to use
Customer-branded surfaces where tenant brand assets should take precedence
Small repeated rows or cards where a logo would be decorative noise
Third-party integration identities - use Avatar, ElementBadge, or vendor-specific icons
Accessibility
Role: link
Enter — Navigates to the owning surface home when rendered as a link
Screen reader: Expose an aria-label such as "Triform docs home". Mark the inline SVG as decorative when the label already names the destination.
Notes: Do not replace the logotype with text. If SVG rendering is unavailable, fall back to the word "Triform" in the display font.
Props
Name
Type
Default
Description
surface_label
string
Docs
Short product or surface label displayed beside the logotype.
href
string
—
Optional home route when the lockup is interactive.
compact
boolean
false
Uses icon mark only when horizontal space is constrained.
A button placed at the end of a list that fetches and appends the next page in place, keeping prior results visible. Use it for feeds and scannable lists where users care about continuity more than jumping to an exact page. The `loading` state shows an in-button spinner; `disabled` covers the "nothing left to load" terminal state. The optional remaining-count caption sets expectations.
Readiness
complete
Preview
live
Props
4
Examples
3
Code
implementation mapped
When to use
Feeds / activity streams where context-continuity matters
Lists where users rarely need a specific page number
Mobile-friendly paging without a full pager control
When not to use
Users need to jump to an arbitrary page — use Pagination
Truly infinite content where a scroll sentinel is better
A standalone primary action — use Button directly
Accessibility
Role: button
Enter — Load the next page
Space — Load the next page
Screen reader: The control is a labelled group containing a real button. The remaining-count caption is aria-hidden decorative text; convey the remaining count in the button label itself if it must be announced.
Notes: While loading, the button reflects a busy state via the shared Button primitive; keep the label stable so focus is not lost.
Props
Name
Type
Default
Description
label
string
Load more
Button label.
loading
boolean
false
Whether a fetch is in-flight (button shows a spinner).
disabled
boolean
false
Disable the button (e.g. nothing left to load).
remaining
integer
—
Optional remaining-count caption (renders 'N more').
Examples
More to load
Default state with a remaining-count caption.
24 more
YAML
type: load-more
props:
label: Load more
remaining: 24
Loading
In-flight fetch.
YAML
type: load-more
props:
label: Load more
loading: true
Disabled
Exhausted list — nothing left to load.
YAML
type: load-more
props:
label: All caught up
disabled: true
A persistent edge affordance that keeps the workspace calm in its collapsed state while making navigation fully accessible through three layered gestures: (1) proximity — approaching the edge reveals the panel as the user nears; (2) hover-keep-open — the panel stays fully unfolded as long as the pointer is over the handle or any panel item, regardless of edge distance; (3) click-to-pin — a click on the handle or an item locks the rail open until the user clicks outside it or opens the opposing rail. The handle and item panel animate as two hinged faces of the same fixed edge: the handle folds back and the panel folds flat toward the user. When two rails share an exclusivity group (e.g. Library left + Properties right), only one can be pinned at a time — clicking one releases the other.
Readiness
complete
Preview
live
Props
7
Examples
3
Code
implementation mapped
When to use
Workspace chrome that should remain discoverable without permanently consuming horizontal space
Category or section rails where items are icon-led and repeated frequently
Dense canvas/editor surfaces where peripheral controls should stay quiet until needed
Paired left/right rails that should be mutually exclusive (the exclusivity_group enforces this automatically)
As a progressive enhancement over click/touch accessible rail controls
When not to use
Primary app navigation that must remain fully readable at all times
Forms, destructive actions, or workflows where hover-only disclosure would hide required context
Mobile-only surfaces without a click/tap fallback
Long text menus that need scanning more than spatial recall
Accessibility
Role: navigation
Tab — Focus enters the collapsed handle, then the expanded item buttons
Enter — Toggles the rail handle or activates the focused item; also pins the rail open
Escape — Clears the pin and collapses focus-opened state
Screen reader: The collapsed handle is a real button with `aria-expanded`. The expanded item panel is a `nav` region with the same accessible label. Active items use `aria-current=true`; disabled items use native disabled semantics. The pinned state is not separately surfaced to assistive technology — the `aria-expanded` state on the handle already communicates open/closed.
Notes: Proximity, hover, and click-to-pin are layered: each adds to the previous. Keyboard focus and handle click keep the rail fully reachable without hover. Reduced-motion users keep all three disclosure gestures but lose the 3D hinge transform. Touch / coarse-pointer devices receive the pinned-open state by default (via the existing `@media (hover:none)` rule).
Props
Name
Type
Default
Description
side
enum: left | right
left
Viewport/container edge the rail is hinged to.
placement
enum: contained | viewport
contained
`contained` renders inside a showcase/demo well; `viewport` mounts as app chrome.
label*
string
—
Accessible label for both the collapsed handle and expanded nav region.
handle_icon*
string
—
Material Symbols icon shown while the rail is collapsed.
open_radius_px
number
28
Distance from the edge where the rail reaches fully-open magnetic strength.
close_radius_px
number
156
Distance from the edge where the rail fully releases and closes.
items*
array
—
Rail items. `id`, `label`, and `icon` are required; `color`, `active`, and `disabled` are optional.
A numbered pager for jumping to a specific page of a bounded result set. Use it when users need direct access to arbitrary pages and the total page count is known. The window keeps a fixed footprint: first page, last page, and `sibling_count` pages either side of the current, with "…" gaps where the sequence breaks. Prev/next are disabled at the ends.
Readiness
complete
Preview
live
Props
3
Examples
3
Code
implementation mapped
When to use
Tables / search results with a known total page count
Users need to jump to a specific or last page
Result sets where page position is meaningful
When not to use
Continuous feeds where continuity matters — use LoadMore
Unknown / unbounded totals — use a scroll sentinel
Fewer than 2 pages (render nothing instead)
Accessibility
Role: navigation
ArrowLeft — Previous page
ArrowRight — Next page
Enter — Activate the focused page / edge button
Screen reader: Wrapped in a nav labelled "Pagination". The current page button is aria-current="page"; each page button has an explicit "Go to page N" label and the edge buttons are labelled "Previous page" / "Next page". Ellipsis gaps are aria-hidden.
Notes: Disabled prev/next at the bounds are real disabled buttons so keyboard and SR users get consistent boundary feedback.
Props
Name
Type
Default
Description
current
integer
1
Current page (1-based).
total
integer
1
Total number of pages.
sibling_count
integer
1
Sibling pages shown either side of the current page.
Examples
Page 6 of 12
Mid-range page in a large result set (ellipsis both sides).
SimpleTabs renders a lightweight tablist when panels are owned by the surrounding view. It provides the shared tab visual language without forcing content into the tab component itself.
Readiness
complete
Preview
live
Props
3
Examples
1
Code
implementation mapped
When to use
Switching between sibling panels in a compact surface
Category, mode, or details tabs where the parent owns panel rendering
A tablist that needs the platform underline, pill, or boxed treatment
When not to use
Tabs that must own and mount panel content; use Tabs with TabPanel
Global navigation between product areas
Binary choices; use Switch, Checkbox, or two explicit buttons
Accessibility
Role: tablist
Tab — Moves focus into and out of the tablist
Enter — Activates the focused tab
Space — Activates the focused tab
Screen reader: Each tab exposes aria-selected to announce the active tab.
Notes: Parent surfaces must connect the active index to the visible panel.
Horizontal tab control for switching between content panels. Three visual variants — Underline (default), Pill, Boxed — share keyboard navigation and ARIA wiring. Pair with `TabPanel` for content. Tabs preserve panel state across switches (mounted-but-hidden), so don't use for content with side-effects on render.
Readiness
complete
Preview
live
Props
2
Examples
2
Code
implementation mapped
When to use
Switching between sibling views (Overview / Settings / Logs)
Filtering a list by status (All / Active / Archived)
Compact navigation inside a panel or modal
Settings pages with grouped sections
When not to use
Routes — use real router links, not tabs
More than ~6 tabs — switch to a Select / Sidebar
Vertical orientation — use VerticalTabs (when it lands)
Disclosure (one open at a time) — use Accordion
Accessibility
Role: tablist
ArrowLeft — Previous tab
ArrowRight — Next tab
Home — First tab
End — Last tab
Tab — Move focus from tablist to current panel
Screen reader: Tablist + tab + tabpanel ARIA pattern. SR users can navigate the tab strip with arrow keys, tab to enter the active panel, and shift-tab back to the tablist.
Notes: Activation is "manual" (Enter to commit) by default. Use "automatic" (focus = activate) for low-cost panel switches. Avoid auto-activation when each tab triggers an expensive load.
Props
Name
Type
Default
Description
active
integer
—
style
enum: underline | pill | boxed
underline
Examples
Settings tabs
Settings page tabs.
YAML
type: tabs
props:
active: ${state.settings_tab}
style: underline
slots:
default:
- type: text
slots:
default: General
- type: text
slots:
default: Members
- type: text
slots:
default: Billing
Pill filter
Pill-style filter tabs above a list.
YAML
type: tabs
props:
active: ${state.filter_tab}
style: pill
slots:
default:
- type: text
slots:
default: All
- type: text
slots:
default: Active
- type: text
slots:
default: Archived
A vertical (left-rail) tab control for switching between sibling views when there are more tabs than fit comfortably horizontally, or when the layout already has a sidebar. Same selection model and ARIA wiring as Tabs, but laid out as a column with aria-orientation="vertical" and Up/Down arrow traversal.
Readiness
complete
Preview
live
Props
2
Examples
2
Code
implementation mapped
When to use
Settings / preferences with many grouped sections
A sidebar + content split where the rail drives the panel
More tabs than fit horizontally without wrapping
When not to use
2–4 peer views that fit horizontally — use Tabs
Disclosure (one open at a time, stacked) — use Accordion
Cross-page navigation — use real router links
Accessibility
Role: tablist
ArrowUp — Previous tab
ArrowDown — Next tab
Home — First tab
End — Last tab
Screen reader: Declares role="tablist" with aria-orientation="vertical". The active tab is aria-selected="true" and is the only tab in the tab order (roving tabindex); other tabs are reachable via the arrow keys, matching the WAI-ARIA tabs pattern.
Notes: Arrow keys wrap (last → first and back). The active tab keeps tabindex=0 so Tab moves focus into the tablist at the right place.
Props
Name
Type
Default
Description
active
integer
0
Currently active tab index.
tabs
array
—
Tab labels.
Examples
Settings rail
Settings sidebar with grouped sections.
YAML
type: vertical-tabs
props:
active: ${state.settings_tab}
tabs:
- General
- Members
- Billing
- Integrations
- Danger zone