Skip to main content

Sticky Button

A button that remains fixed in the viewport as the user scrolls. Use for persistent primary actions that must remain accessible throughout a long page or form. Don't use more than one Sticky Button per view.

Figma Storybook Docs

Description

What it does

Fixes a primary call-to-action button to the bottom of the viewport so it stays visible as the user scrolls through long content. The button overlays page content rather than pushing it, and dismisses or becomes inactive once the action is no longer relevant.

Where it appears

Bottom of long forms, survey pages, consultation submission flows, and multi-section stakeholder engagement pages where the primary action (e.g. Submit, Save, Continue) must remain reachable without scrolling back to the top or bottom of the page.

Why it exists

Government forms and consultation pages are often long and content-heavy. Users — including older adults and those less familiar with digital interfaces — benefit from a persistent, unambiguous call-to-action. The Sticky Button reduces friction and drop-off on high-completion-rate tasks.

Dependencies

Button

Anatomy

PartRequired?Notes
Container Required Fixed-position wrapper anchored to the bottom of the viewport. Carries a drop-shadow to visually separate from scrolled content. Width is full on mobile; constrained to match page content width on wider viewports.
Button Required A single primary Button component inside the container. Inherits all Button variants and states. Should always be the primary variant.
Backdrop overlay Optional A subtle translucent band behind the container that helps the button read against varied page backgrounds. Use when page content behind the button may be visually complex (e.g. maps, images, data tables).
Safe-area inset Recommended Bottom padding that accounts for mobile browser chrome and iOS home indicator (env(safe-area-inset-bottom)). Always apply to avoid the button being obscured on mobile devices.

Variants

Default

Primary action persisted at the bottom of the viewport.

Use for the single most important action on a long page — typically Submit, Save, or Continue.

With count / badge

Communicates pending or selected items relevant to the action.

Use when the action is conditional on selections made on the page, such as 'Submit 3 responses' or 'Add 2 stakeholders'.

States

State Behaviour
Default Button is fully interactive. Label reflects the primary action. Drop-shadow and backdrop are visible.
Hover Button background transitions to --op-color-interactive-hover. Cursor changes to pointer.
Focus 3px focus ring using --op-color-interactive-focus appears around the button. Focus is not clipped by the container.
Active / pressed Button background darkens slightly. Provides tactile feedback on touch devices.
Disabled Button opacity reduces to 40%. Cursor is not-allowed. The sticky container remains visible but the action cannot be triggered. Always pair with an inline explanation of why the action is unavailable.
Loading Button label is replaced by a wa-spinner. Button is non-interactive during loading. aria-label is updated to communicate the in-progress state to screen readers.
Hidden / scrolled past If the natural in-page button position scrolls into view, the sticky button should be hidden to avoid duplication. This is managed via an IntersectionObserver on the in-page anchor element.

Usage guidelines

When to use

  • Long consultation or survey forms where the submit action would otherwise require scrolling to find.
  • Multi-section stakeholder engagement pages with a single terminal action (e.g. finalise engagement plan, publish consultation).
  • Step-within-page flows where the user must scroll to review content before confirming.

When not to use

  • Short pages where the action is already visible without scrolling — use a standard Button instead.
  • When multiple primary actions are needed — sticky buttons must be singular. Use a standard button group or action bar instead.
  • Inside modal dialogs or drawers — use standard Button placement within those components.
  • When the action is destructive (e.g. Delete, Archive) — destructive actions should require deliberate navigation, not a persistent visible trigger.

Do / Don't

Do

Use a single, specific action label (e.g. 'Submit consultation', 'Save stakeholder record').

Don't

Use vague labels like 'OK' or 'Click here'.

Do

Hide the sticky button when the in-page equivalent button scrolls into the viewport.

Don't

Show both the sticky and in-page versions simultaneously — this confuses users and clutters the UI.

Do

Apply safe-area-inset-bottom padding so the button clears mobile browser chrome.

Don't

Hard-code bottom: 0 without the env() safe area inset — it will be obscured on iOS devices.

Do

Disable the button with an accessible reason when prerequisites are not met (e.g. required fields incomplete).

Don't

Hide the button entirely when prerequisites are not met — this removes user orientation.

Do

Keep the container z-index high enough to overlay content but lower than modal/dialog overlays.

Don't

Set z-index arbitrarily high (e.g. 9999) — use the design system z-index scale.

Was this page helpful?

Updated 9 September 2026