Containers
Structural layout components used to group and space related content. Use to establish visual hierarchy and contain distinct page regions. Don't use as a substitute for spacing tokens.
FigmaDescription
Containers wrap related content in a visually bounded region, applying consistent internal padding, background colour, border, and radius to define a distinct section of a page or panel.
Throughout Open Point and Social Point — dashboard cards, stakeholder profile sections, consultation step panels, form groupings, sidebar regions, and modal body areas.
Government interfaces carry dense, multi-domain content. Containers create clear visual boundaries between information regions, reducing cognitive load and helping users identify where one task or topic ends and another begins.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Container root | Required | The outer element (div or semantic equivalent). Sets the background, border, radius, and padding via tokens. |
| Container header | Optional | A heading or labelled region at the top of the container. Anchors the section for screen readers. Use an appropriate heading level (h2-h4) based on page hierarchy. |
| Container body | Required | The main content region inside the container. Receives vertical rhythm via --op-space-* tokens applied to child elements. |
| Container footer | Optional | A bottom row for actions (e.g. Save, Cancel) or meta information (e.g. last updated timestamp). Visually separated from the body using a border or spacing. |
| Border | Optional | A 1px stroke using --op-color-border-default. Omit on containers placed on --op-color-bg-secondary surfaces where background contrast already defines the boundary. |
| Elevation / shadow | Optional | Used selectively on floating containers (drawers, popovers). Not applied to inline page containers. |
Variants
Default
Neutral grouped content region on a primary background.
General grouping of related fields, summaries, or descriptive content within a page section. The most common container type.
Outlined
Container with explicit 1px border, no elevated background.
When the container sits on --op-color-bg-primary and background contrast alone is insufficient to define the boundary. Common in form sections and stakeholder record panels.
Filled (Subtle)
Container with --op-color-bg-secondary background and no border.
De-emphasised groupings such as supplementary information, help text blocks, or read-only data summaries nested within a primary container.
Filled (Accent)
Container with a status or brand-tinted background for callouts.
Contextual highlights — e.g. an active consultation notice, a compliance warning, or an onboarding prompt. Pair with the matching status token (info, warning, success, error).
Flush
Container without padding, radius, or border.
When the container is used purely for structural grouping within a layout grid and visual boundaries are handled by the parent. Do not use where content needs visual separation.
States
| State | Behaviour |
|---|---|
| Default | Static, fully visible. No interaction affordance. Content is readable and actionable. |
| Loading | Container body is replaced by a skeleton loader or wa-spinner. Header and footer remain visible to preserve layout stability. Applied when content is fetched asynchronously (e.g. stakeholder engagement history). |
| Empty | Container body displays an empty-state message with optional CTA. Minimum height is maintained so the page layout does not collapse. Example: 'No submissions yet — share the consultation link to get started.' |
| Error | Container body displays an inline error message using --op-color-status-error and --op-color-status-error-bg. The header and footer remain, allowing retry or navigation actions. |
| Disabled | Entire container and its contents are non-interactive. Opacity reduced to 0.5. Applied when a section is locked pending a prerequisite step (e.g. review stage not yet reached). |
Usage guidelines
When to use
- Grouping a set of related fields within a multi-section form (e.g. 'Contact details', 'Engagement preferences').
- Isolating a summary or read-only record on a stakeholder profile page.
- Wrapping a consultation step or phase panel so users can distinguish it from other steps.
- Creating a card-like region on a dashboard for metrics, activity feeds, or quick actions.
- Containing an aside or supplementary information block (filled-subtle variant) next to primary content.
When not to use
- Do not use a container as a substitute for spacing tokens. Use --op-space-* margins and gaps between elements instead of wrapping them in an extra container.
- Do not nest containers more than two levels deep. Excessive nesting creates visual noise and makes hierarchy ambiguous. Flatten the structure or use dividers instead.
- Do not use the accent-filled container for purely decorative purposes. Reserve status backgrounds for genuine status communication.
- Do not use a container for a single standalone element (e.g. one button or one label). Use spacing tokens directly.
Do / Don't
Do
Apply a descriptive heading inside the container header so screen readers can announce the section.
Don't
Leave containers without a label when they contain distinct functional content — unlabelled regions are confusing for assistive technology users.
Do
Use the outlined or filled-subtle variant consistently across a page to indicate related groupings.
Don't
Mix container variants arbitrarily on the same page — inconsistent boundaries make hierarchy harder to parse.
Do
Keep container padding consistent using --op-space-16 (16px) or --op-space-24 (24px) for body regions.
Don't
Use arbitrary pixel values or mix padding scales within the same container family.
Do
For loading states, retain the container shell (header, footer) and load body content in place.
Don't
Destroy and re-render the entire container on data refresh — this causes layout shift and loses scroll position.
Layout & Spacing
Container padding (body): Default / Outlined / Filled: --op-space-16 (16px) mobile, --op-space-24 (24px) desktop Flush: 0
Container header bottom margin: --op-space-16 (16px) Container footer top margin: --op-space-16 (16px) Footer top border: 1px solid --op-color-border-default (optional, use when footer contains actions)
Gap between stacked containers: --op-space-16 (16px) default, --op-space-24 (24px) when containers are visually prominent sections
Border radius: Default / Outlined / Filled: --op-radius-md (8px) Flush: 0
Tokens
| Part | Token | Value |
|---|---|---|
| Container root background (default) | --op-color-bg-primary | Standard page surface. Used for default and outlined variants. |
| Container root background (filled-subtle) | --op-color-bg-secondary | Slightly recessed surface for supplementary regions. |
| Container root background (filled-accent / info) | --op-color-status-info-bg | Used for informational callout containers. |
| Container root background (filled-accent / warning) | --op-color-status-warning-bg | Used for compliance warning or caution callout containers. |
| Container root background (filled-accent / success) | --op-color-status-success-bg | Used for confirmation or completion callout containers. |
| Container root background (filled-accent / error) | --op-color-status-error-bg | Used for error state containers. |
| Border (outlined variant) | --op-color-border-default | 1px solid. Applied on all four sides. Do not use on filled variants where background contrast defines the boundary. |
| Header text | --op-color-text-primary | Heading level h2-h4 inside the container header. |
| Body text | --op-color-text-primary | Standard body copy inside the container. |
| Secondary / metadata text | --op-color-text-secondary | Timestamps, help text, supplementary labels. |
| Footer border | --op-color-border-default | 1px top border on container footer when actions are present. |
| Disabled overlay | opacity: 0.5 | No separate token — use CSS opacity on the container root. |
| Border radius | --op-radius-md | 8px. Applied uniformly. |
Engineering notes
- Containers are plain HTML elements — there is no Web Awesome (wa-*) container component. Implement using div, section, or article with Orbit utility classes or direct token application.
- Use semantic HTML for the container root: section when the container represents a standalone document section with its own heading, article for self-contained content (e.g. a stakeholder record card), div for purely layout-structural groupings.
- Always include an aria-labelledby attribute on section and article containers, pointing to the container's heading id. This gives screen reader users a navigable landmark.
- Apply container styles via CSS custom properties rather than hardcoded values so that theme overrides (e.g. dark mode, high-contrast) propagate automatically.
- For loading states, use aria-busy='true' on the container root and replace body content with a wa-spinner or skeleton. Remove aria-busy once content has loaded.
- Do not apply role='region' explicitly unless the container has a visible label. Unlabelled regions add noise to the accessibility tree without benefit.
- When a container is disabled, add aria-disabled='true' to the root and ensure all interactive children are also individually disabled. CSS pointer-events: none alone is not sufficient for keyboard users.
- Avoid inline style attributes for token values in production code. Use a shared CSS class (e.g. .op-container, .op-container--outlined) that maps to tokens.
Keyboard interaction
| Key | Action |
|---|---|
| Tab | Moves focus to the next interactive element inside the container. Containers themselves are not focusable unless they contain interactive content. |
| Shift+Tab | Moves focus to the previous interactive element inside or before the container. |
| Enter | Activates a focused interactive element within the container (button, link). No action on the container root itself. |
Why it matters
Government platforms serve users with diverse assistive technology needs, including screen reader users navigating complex multi-section pages such as consultation submissions or stakeholder records. Properly labelled containers create navigable landmarks that allow users to jump directly to relevant sections without reading the entire page.
Focus
Container roots are not focusable (no tabindex). Focus moves through interactive children in DOM order. When a container transitions from loading to loaded state, focus should remain on the last focused element (or move to the first interactive element inside the container if focus was on the spinner). Disabled containers must trap no focus — all children must be individually disabled or removed from the tab order.
ARIA
| Role or attribute | When to use | Example |
|---|---|---|
aria-labelledby | Applied to section and article container roots. Points to the id of the container's heading element. | <section aria-labelledby="contact-details-heading"><h2 id="contact-details-heading">Contact details</h2>...</section> |
aria-busy | Set to true on the container root during async content loading. Removed when loading completes. | <section aria-labelledby="activity-heading" aria-busy="true"><wa-spinner label="Loading activity"></wa-spinner></section> |
aria-disabled | Applied to the container root when the entire section is non-interactive. Must be paired with disabling all interactive children. | <section aria-labelledby="review-heading" aria-disabled="true">...</section> |
role="region" | Only used when the container needs to be a named landmark and a native semantic element (section, article) is not appropriate. Requires an accessible name via aria-label or aria-labelledby. | <div role="region" aria-labelledby="summary-heading">...</div> |
Contrast
Default container background (--op-color-bg-primary) with body text (--op-color-text-primary): meets WCAG AA (4.5:1 minimum for normal text). Filled-subtle container background (--op-color-bg-secondary) with body text (--op-color-text-primary): verify contrast ratio meets 4.5:1 — do not use --op-color-text-secondary for body content on this surface. Status-tinted backgrounds (--op-color-status-*-bg) with their corresponding text tokens: always verify at the theme level. Do not assume status tokens meet contrast requirements without checking — tinted backgrounds can fail if paired with mid-tone text. Border (--op-color-border-default) against container background: not required to meet 3:1 for non-text elements per WCAG 1.4.11, but recommended to avoid relying solely on colour to convey boundary.
Touch targets
Container roots themselves have no touch target requirement. Interactive elements inside containers (buttons, links, form controls) must meet the 44x44px minimum touch target size independently.
Things to avoid
- Do not use colour alone to distinguish container variants — outlined vs filled variants should also differ in border presence or padding, not just background colour.
- Do not place focusable elements inside a disabled container without also disabling them individually — keyboard users will still reach them via Tab.
- Do not apply aria-hidden='true' to a container that has visible, meaningful content — this hides it entirely from screen readers.
- Do not rely on visual nesting alone to imply hierarchy — use heading levels inside containers to communicate structure programmatically.