Guide cue (one-shot onboarding tooltip)
One-shot tooltip-style component with arrow + title + body + optional CTA, surfaces a single feature discovery, persists per-user so it never re-shows after dismissal. Modeled after MongoDB LeafyGreen GuideCue.
Component — Guide cue
*tatus* v0.1.0 — Draft. Sits between info-sprinkle (lightweight inline help) and callout-card (full surface nudge) on the affordance weight spectrum.
R1 — Anatomy
- Arrow indicator pointing at the highlighted feature.
- Title (1 short sentence).
- Body (1–2 sentences).
- Dismiss (×) top
right; keyboardaccessible. - Optional CTA (verb, 1–3 words:
Try it,Show me).
R2 — Positioning
- Uses Floating UI semantics: choose side (toprightbottom/left) based on available viewport space.
- Arrow always points at the anchor element's nearest edge.
- 8px gap between arrow tip and anchor element.
R3 — Trigger
- *ount
ontrigger* cue appears X ms after the anchor element mounts (default 800ms; configurable). - *how()* imperative API to surface cue on demand (rare; usually mount
ontrigger). - Does NOT trigger on hover/focus (that's info-sprinkle's job).
R4 — Persistence
- Each cue carries a stable
cue_id. - On dismiss (× or CTA click) the cue NEVER re-shows for that user + cue_id pair.
- Storage:
- Authenticated: persisted via Koder ID profile (cross-device).
- Unauthenticated: localStorage with key
koder.guide_cue.{cue_id}=dismissed.
- Resetting cues (admin / dev mode):
koder.guide_cue.*localStorage clearance + Koder ID profile reset (consumer feature, not KDS-managed).
R5 — Accessibility
- Container:
role="dialog"witharia-modal="false"(does NOT trap focus; user can ignore). aria-labelledbypoints at title;aria-describedbypoints at body.- Initial focus does NOT move into the cue — the anchor element keeps focus to avoid hijack.
- Tab from anchor enters the cue (title → body → CTA → dismiss).
- Esc dismisses (counts as a dismissal — never re-shows).
R6 — Multiple cues on a page
- One visible cue per page at a time.
- If multiple cues are eligible to show, queue them in mount order.
- After a cue dismisses, wait 500ms before showing the next (prevents stacking).
R7 — Animation
- Default: fade + 4px slide
in toward the anchor, 200ms easeout. prefers-reduced-motion: reduce: instant appear, no slide.
R8 — OUIA
Per specs/testing/ouia-test-hooks.kmd:
data-ouia-component-type="GuideCue"data-ouia-component-id="<cue-id>"data-ouia-safe="true"only when visible and animation complete.
Não-escopo
- Tour sequencing (multi-cue narrative with Next/Previous) — separate ticket if demand surfaces.
- Server-side analytics on cue impression / dismiss (consumer concern).