Tap Hint
A small pulsing "tap here" badge that points at an interactive element. Solves the mobile touch-affordance gap: on desktop, hover gives feedback that an element is interactive — on touch there is nothing. Drop a TapHint next to a target with the position you want it to sit on, and the pointer rotates so it always aims back at the target.
Preview
top
topright
rightbottom
bottomleft
leftInstallation
npx shadcn@latest add https://craftbits.dev/r/tap-hint.jsonUsage
import { TapHint } from "@craft-bits/core";
<div className="relative inline-block">
<button>Add to cart</button>
<div className="absolute -bottom-9 left-1/2 -translate-x-1/2">
<TapHint position="bottom" label="tap here" />
</div>
</div>Custom label and side:
<TapHint position="right" label="drag me" />Icon-only (no label):
<TapHint position="top" label="" />Anatomy
- Pointer icon — rotates per
positionso the nib always aims back at the target. The accent color makes it pop against the badge fill. - Pill — a soft
--cb-bg-elevatedbackground with a hairline--cb-border-mutedring. Carries arole="note"and ignores pointer events. - Label — short action text next to the icon (
tap,drag me,from right). Pass an empty string to render the icon alone. - Idle bob — both icon and label drift 2px in the direction of the target on a 2-second loop, gesturing toward where the user should aim.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
position | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | Which side of the target the hint sits on. Drives pointer rotation and bob direction. |
label | string | 'tap' | Short action label next to the icon. Pass an empty string to render the icon alone. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- Renders as
<div role="note">so assistive tech announces it as supplementary content. - The pointer icon is
aria-hidden="true"so only the label is read aloud. pointer-events: noneon the root — the badge never blocks the underlying target from receiving taps.- Bob motion is small (2px) and slow (2s period) so it stays comfortable for motion-sensitive users; suppress at the parent if you need to honour
prefers-reduced-motionexactly.
Credits
- Extracted from:
algoflashcards(src/lessons/primitives/chrome/TapHint.tsx). The source primitive wrapped its target in a flex column and rendered a hint badge below; it also owned its own auto-dismiss-on-tap state. The craft-bits version is presentational only and exposes apositionprop so consumers can place the hint on any side of their target, with the pointer icon rotating to match.