Coachmark
A coachmark is an anchored popover that spotlights and explains a single feature, typically used in onboarding, feature discovery, or guided tours.
Use it sparingly and at most one at a time, paired with a visual anchor on the feature being highlighted. A coachmark teaches; it should not block the user from continuing their task.
Implementation Notes
- Uses a
<div>withrole="dialog"andaria-modal="false"(non-blocking) titleis rendered in an<h2 class="coachmark-title">and linked viaaria-labelledbydescription, when provided, is rendered in a<p class="coachmark-description">and linked viaaria-describedby- The dismiss button always renders and uses
dismissLabelasaria-label - The whole coachmark is hidden via the
hiddenattribute whenopenisfalse - IDs for the title and description are generated stably via
useId,crypto.randomUUID, or a Math.random helper
Props
open: boolean (defaultfalse) -- whether the coachmark is visibletitle: string (required) -- heading textdescription: string (optional) -- body textdismissLabel: string (required) -- accessible label for the dismiss buttononDismiss/ondismiss: callback (optional) -- dismiss click handler...restProps: any additional HTML attributes
Usage
<Coachmark
open={open}
title="Try the new filter"
description="Filter by status to find items faster."
dismissLabel="Dismiss"
onDismiss={handleDismiss}
/>
Keyboard Interactions
- Tab / Shift+Tab: Move focus into and out of the coachmark
- Enter / Space: Activate the dismiss button when focused
- Escape: (Consumer-provided) call
onDismissto close the coachmark
ARIA
role="dialog"on the containeraria-modal="false"(non-blocking; does not trap focus or hide background)aria-labelledbyreferences the title idaria-describedbyreferences the description id (only when description is provided)hiddenattribute reflects!open
When to Use
- Use for onboarding a single new feature
- Use for guided tours that highlight one element at a time
- Use when the dismissal is non-blocking and the user can continue working
When Not to Use
- Do not use for blocking confirmations — use
DialogorAlertDialog - Do not stack multiple coachmarks at once — sequence them
- Do not use for help that should be persistently available — use
ContextualHelporTooltip
Headless
Renders a <div role="dialog" aria-modal="false"> with title/description ids and an always-rendered dismiss button. Anchor positioning, fade/scale animations, and visual treatment are entirely the consumer's responsibility.
Styles
Consumer CSS targets the coachmark class. Sub-elements expose coachmark-title, coachmark-description, and coachmark-dismiss classes for selective styling. Provide a clear focus indicator on the dismiss button.
Testing
- Verify the component renders a
<div>withrole="dialog"and classcoachmark - Verify
aria-modal="false" - Verify the title is rendered inside
<h2 class="coachmark-title">and linked viaaria-labelledby - Verify the description, when provided, is rendered and linked via
aria-describedby - Verify the description and
aria-describedbyare absent when no description is provided - Verify
hiddenis set whenopenisfalse - Verify the dismiss button has
aria-label={dismissLabel}and firesonDismisson click
Advice
- Designers: Anchor the coachmark visually to the feature; do not obscure other actions.
- Developers: Persist the dismissed state in user preferences so the coachmark does not reappear.
Related components
popover— a floating content box anchored to a trigger elementtooltip— a small popup showing descriptive text on hover or focustour— a tour guide, such as for sightseeing, or pathways, or demonstrations, etc.
References
- WAI-ARIA Dialog: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
- Adobe Spectrum Coachmark: https://spectrum.adobe.com/page/coach-mark/
- WCAG 1.4.13 Content on Hover or Focus: https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus