Skip to main content

CloseButton

A small dismissal button displaying an × icon. Use to close or dismiss modals, alerts, drawers, or tags. Don't use for destructive or irreversible actions — use a labelled Button with Destructive intent instead.

OverviewStyleAccessibility

Description

Anatomy

PartRequired?Notes
Button root Required Native
Icon (×) Required A wa-icon or inline SVG rendering a close/times glyph at 16px. Must not carry standalone meaning — the accessible label is on the button root.
Accessible label Required aria-label or visually hidden text (e.g. 'Close modal', 'Dismiss alert', 'Remove tag: Stakeholder name') read by screen readers. Never left empty.
Focus ring Required 3px solid ring using --op-color-interactive-focus, always visible on keyboard focus. Not suppressed on mouse interaction.
Touch target overlay Recommended Minimum 44x44px interactive area regardless of visual icon size, achieved via padding or an invisible pseudo-element.

Variants

States

State Behaviour
Default (rest) Icon renders at --op-color-text-secondary. No background fill.
Hover Background fills to --op-color-interactive-hover at low opacity (8-12%). Icon shifts to --op-color-text-primary. Cursor becomes pointer.
Focus 3px focus ring using --op-color-interactive-focus appears around the button. Background fill matches hover state. Must be visible for both keyboard and programmatic focus.
Active (pressed) Background deepens slightly (--op-color-interactive-default at 16% opacity). Icon scales to 95% if motion is not reduced.
Disabled Icon renders at --op-color-text-disabled. Pointer events removed. aria-disabled='true' set. Do not use disabled state when the parent element is already not dismissible — simply omit the button.

Usage guidelines

Do / Don't

Do

Always provide a descriptive aria-label that includes the name of what is being closed (e.g. 'Close Add Stakeholder modal').

Don't

Don't use a bare aria-label of 'Close' when multiple CloseButtons are present on the same page — screen reader users will hear duplicate, ambiguous button names.

Do

Position the CloseButton consistently in the top-right corner of modals and drawers to match user expectations established by common OS and browser patterns.

Don't

Don't place CloseButton at the bottom of a modal where it competes visually with primary action buttons.

Do

Return focus to the element that triggered the parent overlay when the CloseButton is activated.

Don't

Don't drop focus to the top of the document or to a generic container after dismissal.

Do

Use the Ghost variant inside Tag components so the button does not dominate the tag's visual weight.

Don't

Don't apply the Default variant inside small Tag components — the background fill will visually overpower the tag label.

Layout & Spacing

Button root: width and height minimum 44px (touch target); visual icon container 28x28px centred within. Icon size: 16px (1rem). Internal padding (visual): --op-space-8 (8px) all sides. Gap from adjacent content (e.g. modal title): --op-space-12 (12px). Ghost variant removes background; padding unchanged to preserve touch target. Border radius: --op-radius-sm (4px) for Default and On-colour; --op-radius-pill for Ghost inside tags.

Tokens

PartTokenValue
Icon (rest) --op-color-text-secondary Provides sufficient contrast on --op-color-bg-primary without drawing attention away from primary content.
Icon (hover / focus) --op-color-text-primary Increases contrast on interaction to signal affordance.
Icon (disabled) --op-color-text-disabled Signals non-interactivity without relying on opacity alone.
Hover background --op-color-interactive-hover Applied at 8-12% opacity over the button's background. On-colour variant uses white at 15% opacity.
Active background --op-color-interactive-default Applied at 16% opacity for pressed state depth cue.
Focus ring --op-color-interactive-focus 3px solid, offset 2px. Always rendered — never conditional on input method.
On-colour icon --op-color-bg-primary White icon on status-tinted backgrounds (--op-color-status-info-bg, -success-bg, -warning-bg, -error-bg).

Engineering notes

  • Use a native
  • Always bind the aria-label dynamically when the CloseButton is inside a modal or drawer — include the panel title so screen reader users can identify which overlay they are closing (e.g. aria-label='Close Consultation Settings drawer').
  • For tag removal, construct the label from the tag's text content: aria-label='Remove tag: Metro North stakeholders'.
  • Wire up focus return explicitly: store a ref to the trigger element before opening the overlay, and call .focus() on it inside the close handler.
  • Respect prefers-reduced-motion: wrap any scale or transform on the active state in a @media (prefers-reduced-motion: no-preference) block.
  • The component is currently implemented as a plain HTML pattern — a Web Awesome wa-button[variant='neutral'][appearance='plain'][circle] wrapping wa-icon[name='xmark'] is the recommended migration target when upgrading to the stable pattern.

Keyboard interaction

KeyAction
Tab Moves focus to the CloseButton. Focus ring appears.
Enter Activates the dismiss action — closes the modal, drawer, alert, or removes the tag.
Space Activates the dismiss action (native button behaviour).
Escape When focus is inside a modal or drawer, Escape should also trigger the same dismiss behaviour as the CloseButton. The CloseButton itself does not own this handler — the parent overlay does.

Why it matters

Government digital services are used by people with a wide range of assistive technologies, including screen readers, switch access devices, and voice control software. An unlabelled icon button is completely opaque to screen reader users and cannot be reliably targeted by voice control ('Click X' will not match an empty label). Clear, contextual labels also reduce errors for users who navigate non-visually and may have multiple overlapping dialogs open simultaneously.

Focus

On activation: focus moves to the first interactive element in the newly visible content (modal body, next focusable item after a dismissed alert, or the tag input field after a tag is removed). On close/dismiss: focus returns to the element that originally triggered the parent overlay. If the trigger no longer exists in the DOM (e.g. the row was deleted), focus moves to the nearest logical predecessor. Focus trap: the CloseButton participates in the focus trap of its parent modal or drawer — Tab and Shift+Tab should cycle within the overlay until it is dismissed.

ARIA

Role or attributeWhen to useExample
aria-label Mandatory on every CloseButton instance. Describes both the action and the target. <button type="button" aria-label="Close Add Stakeholder modal">...</button>
aria-label (tag removal) For tag dismiss buttons, include the tag text so removal is unambiguous. <button type="button" aria-label="Remove tag: Eastern Region">...</button>
aria-disabled Set to 'true' when the button is in the disabled state. Do not use the HTML disabled attribute alone — it removes the element from the tab order and prevents screen readers from announcing it. <button type="button" aria-disabled="true" aria-label="Close modal">...</button>

Contrast

Default variant: --op-color-text-secondary icon on --op-color-bg-primary background. Verify minimum 3:1 contrast ratio for non-text graphical elements (WCAG 1.4.11). On-colour variant: white (--op-color-bg-primary) icon on status background tokens. --op-color-status-warning-bg requires special attention — the yellow tint may not provide sufficient contrast with a white icon; use --op-color-text-primary (dark) icon on warning backgrounds instead. Hover/active state background tints must not reduce icon contrast below 3:1.

Touch targets

The interactive area must be at least 44x44px on all viewports, including mobile browsers used to access Social Point community consultations. If the visible button is smaller than 44px, use padding or a ::before pseudo-element to expand the hit area without affecting layout.

Things to avoid

  • Using aria-hidden='true' on the button to hide it from screen readers — this removes the only dismiss affordance for non-visual users.
  • Relying solely on the x character as the label — character rendering varies across screen readers and locales.
  • Implementing the button as a clickable div or span — this requires manually adding role='button', tabindex='0', and keydown handlers, all of which are error-prone.
  • Suppressing the focus ring for mouse users via :focus:not(:focus-visible) without careful testing — some users navigate by mouse but still rely on visible focus cues due to cognitive disabilities.
  • Placing the CloseButton outside the modal's focus trap so keyboard users can tab past the overlay into background content.

Was this page helpful?

Updated 2 October 2026