Skip to main content

Component Model

ttoss Components is built on the rule:

a component has an identity, and an instance has a role in composition.

This model is organized into two categories:

  • Component Identity — what the component is
  • Composition Model — how an instance participates in composition

These categories are expressed through three dimensions:

  • Responsibility — the component’s semantic identity
  • Host — the compositional structure where the instance participates
  • Role — what the instance does inside that host

That is the full model.

The model

A component is defined first by its Responsibility. When composition matters, an instance may then participate through a Host and a Role.

In practice:

  • Component IdentityResponsibility
  • Composition ModelHost.Role

This keeps the public component model small and stable while still allowing ttoss to express real interface composition.

Responsibility

Responsibility defines the public semantic identity of a component.

It answers:

  • What is this component?

Every public ttoss component must have exactly one Responsibility.

ResponsibilityUse forTypical examples
Actiontriggering actions or commandsbutton, action button, icon button
Inputdirect user inputtext field, text area, search field
Selectionchoosing one or more optionscheckbox, radio group, select, picker
Collectionstructured sets of itemsmenu, list, table, tree, grid
Navigationmovement across destinations or viewslink, breadcrumbs, tabs, nav item
Disclosurerevealing or hiding related content in placeaccordion, disclosure trigger
Overlaytemporary layered UI above the interfacedialog, popover, tooltip, drawer
Feedbackcommunicating state, status, or outcomealert, banner, toast, progress
Structureorganizing interface structure and support surfacespanel, section, shell, frame

Composition Model

A Host defines the compositional structure. It answers:

  • What kind of composition is this?
HostUse for
ActionSetgroups of actions in the same surface
FieldFramefields and their supporting elements
ItemFrameinternal structure of items in collections
SurfaceFramestructured surfaces and their internal regions

A Role defines what an instance does inside a Host. It answers:

  • What is this instance doing here?

Use Host.Role only when structured composition matters. When Host.Role is absent (standalone components), the component resolves tokens from its Responsibility default.

Composition refines that default through Host.Role.

Summary Table

HostRoleUse for
ActionSetprimarythe main action of the set
ActionSetsecondarysupporting or alternative actions
ActionSetdismissleaving or closing without committing
FieldFramecontrolthe main input control
FieldFramelabelthe field label
FieldFramedescriptionsupporting or helper text
FieldFrameleadingAdornmentcontent before the control
FieldFrametrailingAdornmentcontent after the control
FieldFramevalidationMessagevalidation or error feedback
ItemFramelabelthe main item label
ItemFramedescriptionsupporting item text
ItemFramesupportingVisualicon, avatar, or supporting visual
ItemFrametrailingMetatrailing metadata or secondary value
ItemFrameselectionControlcheckbox, radio, or selection affordance
SurfaceFramemediavisual media region
SurfaceFrameheadingheading region
SurfaceFramebodymain supporting content
SurfaceFrameactionsactions area
SurfaceFramestatusstatus or feedback area

How to use the model

Use the model in this order:

1. Choose the Responsibility

Start by classifying the component itself. Ask:

  • What is this component?

Examples:

  • ButtonAction
  • SearchFieldInput
  • MenuCollection
  • DialogOverlay

2. Add Host and Role when composition matters

If the instance participates in a structured composition, assign a Host and a Role. Ask:

  • What composition is this part of?
  • What is this instance doing inside it?

Examples:

  • Button in a dialog footer → ActionSet.primary
  • Text under a field label → FieldFrame.description
  • Icon inside a menu item → ItemFrame.supportingVisual
  • Buttons inside a card → SurfaceFrame.actions

3. Resolve semantic tokens from the model

Once Responsibility and Host.Role are clear, resolve tokens by foundation.

Use the model to choose:

  • color → semantic color tokens
  • typography → semantic text.* styles
  • spacing → semantic spacing tokens
  • sizing → semantic sizing tokens
  • elevation → semantic elevation tokens when relevant
  • radii → semantic radii aliases when relevant

Quick examples:

  • Action + ActionSet.primaryaction.primary.*
  • Action + ActionSet.secondaryaction.secondary.*
  • Action + ActionSet.dismiss → usually action.muted.*
  • Structure + FieldFrame.label → usually text.label.md
  • Structure + FieldFrame.description → usually text.body.sm + content.muted.text.default
  • Structure + ItemFrame.supportingVisual → usually icon.md + a semantic *.text.* color
  • Structure + SurfaceFrame.heading → usually text.title.md
  • Structure + SurfaceFrame.body → usually text.body.md

The model defines meaning first.
Tokens then express that meaning through each foundation.

Usage Examples

  • button save → Action + ActionSet.primary

    • color: action.primary.background.default, action.primary.text.default
    • typography: text.label.md
    • spacing/sizing: spacing.inset.control.md, hit.default
    • radius: radii.control
  • button back to editing → Action + ActionSet.secondary

    • color: action.secondary.background.default, action.secondary.text.default
    • typography: text.label.md
    • spacing/sizing: spacing.inset.control.md, hit.default
    • radius: radii.control
  • button cancel → Action + ActionSet.dismiss

    • color: action.muted.text.default
    • typography: text.label.md
    • spacing/sizing: spacing.inset.control.md, hit.default
    • radius: radii.control

Search field

  • main field control → Input + FieldFrame.control

    • color: input.primary.border.default, input.primary.background.default, input.primary.text.default
    • typography: text.body.md
    • spacing/sizing: spacing.inset.control.md, hit.default
    • radius: radii.control
  • field label text → Structure + FieldFrame.label

    • color: content.primary.text.default
    • typography: text.label.md
  • helper text → Structure + FieldFrame.description

    • color: content.muted.text.default
    • typography: text.body.sm
  • leading search icon → Structure + FieldFrame.leadingAdornment

    • color: content.muted.text.default
    • sizing: icon.md
    • spacing: usually grouped with the control through spacing.gap.inline.sm
  • menu item label text → Structure + ItemFrame.label

    • color: navigation.primary.text.default
    • typography: text.label.md
  • item description text → Structure + ItemFrame.description

    • color: content.muted.text.default
    • typography: text.body.sm
  • leading icon → Structure + ItemFrame.supportingVisual

    • color: navigation.secondary.text.default or content.muted.text.default
    • sizing: icon.md

Card or panel

  • container → Structure

    • color: content.primary.background.default
    • spacing: spacing.inset.surface.md
    • radius: radii.surface
    • elevation: elevation.resting
  • title text → Structure + SurfaceFrame.heading

    • color: content.primary.text.default
    • typography: text.title.md
  • body content → Structure + SurfaceFrame.body

    • color: content.primary.text.default
    • typography: text.body.md
    • spacing: spacing.gap.stack.sm
  • action buttons → Action + SurfaceFrame.actions

    • spacing: spacing.separation.interactive.min
    • tokens for each button still come from their own role in the action set they form

Rules

1. Responsibility is always primary

Responsibility defines the component itself.

2. Host never replaces Responsibility

Host exists only to model composition.

3. Role is always host-bound

A Role has no meaning outside its Host.

4. Keep the model small

Do not create new Responsibilities, Hosts, or Roles casually.
The goal is a system that stays clear, stable, and reusable.