Contextual Help
A contextual help is a small help button — often a question-mark glyph — that opens a popover with explanatory content for a nearby field, control, or concept.
Use it next to labels and headings where users may need extra explanation on demand without cluttering the primary UI. The help content is hidden by default and revealed only when the user requests it.
Example
Show demo markup
<div class="contextual-help" aria-label="a help button that opens a popover with explanatory content">ContextualHelp</div>
Usage example
<script lang="ts">
import ContextualHelp from './ContextualHelp.svelte';
let open = $state(false);
</script>
<ContextualHelp label="Help with this field" expanded={open} onclick={() => (open = !open)}>
<p>Why we ask: this helps verify your account.</p>
</ContextualHelp>
Show Svelte source
// In your Svelte component:
import ContextualHelp from "lily-design-system-svelte-headless/components/ContextualHelp/ContextualHelp.svelte";
<ContextualHelp>
<!-- content -->
</ContextualHelp>
Usage
<ContextualHelp
label="Help for username"
expanded={open}
onClick={handleToggle}
>
<h3>Username</h3>
<p>Use 3-20 characters. Letters, numbers, and underscores only.</p>
</ContextualHelp>
Props
label: string (required) -- aria-label for the help trigger button
expanded: boolean (default false) -- whether the popover is open
onClick / onclick: callback (optional) -- trigger click handler
children: slot -- popover content
...restProps: any additional HTML attributes
Keyboard Interactions
- Tab / Shift+Tab: Move focus into and out of the trigger and panel
- Enter / Space: Activate the trigger to toggle the popover
- Escape: (Consumer-provided) close the popover when open
ARIA
- Trigger:
aria-label, aria-haspopup="dialog", aria-expanded, aria-controls={panelId}
- Panel:
role="dialog", id={panelId}, hidden when closed
When to Use
- Use to add optional explanatory content next to a field, label, or concept
- Use when help should not occupy persistent space in the layout
- Use when the help is short and self-contained
When Not to Use
- Do not use for required instructions — show those inline as
Hint text
- Do not use for blocking confirmations — use
Dialog or AlertDialog
- Do not use for guided tours — use
Coachmark or Tour
Headless
Renders a <button> trigger and a <div role="dialog"> panel linked by aria-controls. Open/close state, positioning relative to the trigger, animation, and visual treatment are entirely the consumer's responsibility.
Styles
Consumer CSS targets the contextual-help wrapper, contextual-help-trigger button, and contextual-help-panel panel classes. Provide a clear focus indicator on the trigger and ensure the panel is reachable by keyboard.
Testing
- Verify the wrapper renders a
<div> with class contextual-help
- Verify the trigger renders a
<button> with aria-label={label}
- Verify the trigger has
aria-haspopup="dialog"
- Verify
aria-expanded on the trigger reflects expanded
- Verify
aria-controls on the trigger matches the panel id
- Verify the panel renders with
role="dialog" and the matching id
- Verify the panel uses
hidden when expanded is false
- Verify the panel id is stable
Advice
- Designers: Use a recognizable help affordance (e.g., a question mark in a circle); do not rely on color alone.
- Developers: Generate panel ids server-side or with
useId to remain hydration-stable.
Implementation Notes
- Uses a
<div> wrapper with class contextual-help
- The trigger is a
<button class="contextual-help-trigger" type="button"> with aria-haspopup="dialog"
expanded reflects open state on the trigger via aria-expanded
- The trigger references the panel via
aria-controls={panelId}
- The panel is a
<div class="contextual-help-panel" role="dialog"> and is hidden via the hidden attribute when closed
- The panel id is generated stably via
useId, crypto.randomUUID, or a Math.random helper
Related components
tooltip — a small popup showing descriptive text on hover or focus
popover — a floating content box anchored to a trigger element
details — a disclosure widget that shows and hides content
References
- WAI-ARIA Dialog: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
- Adobe Spectrum Contextual Help: https://spectrum.adobe.com/page/contextual-help/
- WCAG 1.3.1 Info and Relationships: https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships
Canonical contract
Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata
- Component: contextual-help
- PascalCase: ContextualHelp
- Description: a help button that opens a popover with explanatory content
- Status: beta — implemented and unit-tested in all seven frameworks with an axe-clean demo page; not yet exercised in composed flows
- HTML tag: <div> wrapper with <button> trigger and <div role="dialog"> panel
- CSS class: .contextual-help
- Interactive: yes
ARIA
- Trigger: aria-label, aria-haspopup="dialog", aria-expanded, aria-controls
- Panel: role="dialog", matching id, hidden attribute when closed
Keyboard
- Tab / Shift+Tab: Move focus into and out of the trigger and panel
- Enter / Space: Toggle the popover when the trigger is focused
- Escape: (Consumer-provided) close the popover
Props
label: string (REQUIRED) -- aria-label for the trigger expanded: boolean (default false) onClick / onclick: callback (optional) children: slot -- popover content ...restProps: any additional HTML attributes