Components
Hint, HintHotspot, and HintTooltip components: add pulsing beacons and floating tooltips for feature discovery
Hint Components
Why Use Hints?
Hints are persistent UI elements that draw attention to features without interrupting the user flow. Unlike tours (which are sequential and modal), hints:
- Stay visible until explicitly dismissed
- Don't block user interaction with the page
- Guide discovery of features users might miss
- Persist across sessions when configured
Use hints for:
- New feature announcements
- Contextual help on complex UI elements
- Onboarding nudges that don't require immediate action
- Feature discovery for power users
Hint
The main component that combines a pulsing hotspot with a tooltip. This is the recommended way to add hints to your app.
Basic Usage
import { HintsProvider, Hint } from '@tour-kit/hints';
function App() {
return (
<HintsProvider>
<Hint
id="new-feature"
target="#export-button"
content="New! Export your data to CSV or PDF"
/>
<button id="export-button">Export</button>
</HintsProvider>
);
}Props
Prop
Type
Styling Variants
// Small - subtle indicators
<Hint id="subtle" target="#element" content="..." size="sm" />
// Default - standard size
<Hint id="normal" target="#element" content="..." size="default" />
// Large - prominent indicators
<Hint id="prominent" target="#element" content="..." size="lg" />// Primary (default)
<Hint id="primary" target="#element" content="..." color="default" />
// Secondary
<Hint id="secondary" target="#element" content="..." color="secondary" />
// Success - for positive features
<Hint id="success" target="#element" content="New!" color="success" />
// Warning - for important features
<Hint id="warning" target="#element" content="Required" color="warning" />
// Destructive - for dangerous actions
<Hint id="danger" target="#element" content="Caution" color="destructive" />// Hotspot positions relative to target element
<Hint id="tl" target="#element" position="top-left" content="..." />
<Hint id="tr" target="#element" position="top-right" content="..." />
<Hint id="bl" target="#element" position="bottom-left" content="..." />
<Hint id="br" target="#element" position="bottom-right" content="..." />
<Hint id="c" target="#element" position="center" content="..." />Using Refs
import { useRef } from 'react';
import { HintsProvider, Hint } from '@tour-kit/hints';
function App() {
const buttonRef = useRef<HTMLButtonElement>(null);
return (
<HintsProvider>
<Hint
id="ref-hint"
target={buttonRef}
content="This hint targets a ref"
/>
<button ref={buttonRef}>Target Button</button>
</HintsProvider>
);
}Rich Content
<Hint
id="rich-hint"
target="#feature"
content={
<div className="space-y-2">
<p className="font-semibold">New Feature!</p>
<p className="text-muted-foreground">
You can now export your data in multiple formats.
</p>
<button className="text-primary underline">Learn more</button>
</div>
}
/>
// Or use children for custom content
<Hint id="custom-hint" target="#feature" content="">
<div className="space-y-2">
<h4>Custom Content</h4>
<p>Using children prop for full control</p>
</div>
</Hint>HintHotspot
The pulsing indicator that appears near the target element. Use this directly for advanced customization.
Basic Usage
import { HintHotspot } from '@tour-kit/hints';
function CustomHint({ targetRect }: { targetRect: DOMRect }) {
return (
<HintHotspot
targetRect={targetRect}
position="top-right"
onClick={() => console.log('Clicked!')}
/>
);
}Props
Prop
Type
Pulse Behavior
The hotspot automatically stops pulsing when the tooltip is open:
const [isOpen, setIsOpen] = useState(false);
<HintHotspot
targetRect={rect}
position="top-right"
isOpen={isOpen} // Pulse stops when true
onClick={() => setIsOpen(!isOpen)}
/>asChild Pattern
Use asChild to render a custom element:
<HintHotspot
targetRect={rect}
position="top-right"
asChild
>
<MyCustomButton className="my-hotspot" />
</HintHotspot>HintTooltip
The floating tooltip that appears when a hint is activated.
Basic Usage
import { HintTooltip } from '@tour-kit/hints';
function CustomTooltip({ target, onClose }: { target: HTMLElement; onClose: () => void }) {
return (
<HintTooltip
target={target}
placement="bottom"
onClose={onClose}
>
<p>This is the tooltip content</p>
</HintTooltip>
);
}Props
Prop
Type
Placement Options
The tooltip uses floating-ui for positioning with automatic collision detection:
// Basic placements
<HintTooltip placement="top" {...props} />
<HintTooltip placement="bottom" {...props} />
<HintTooltip placement="left" {...props} />
<HintTooltip placement="right" {...props} />
// With alignment
<HintTooltip placement="top-start" {...props} />
<HintTooltip placement="top-end" {...props} />
<HintTooltip placement="bottom-start" {...props} />
<HintTooltip placement="bottom-end" {...props} />Custom Close Button
<HintTooltip
target={target}
onClose={handleClose}
closeButton={
<button
onClick={handleClose}
className="absolute right-2 top-2 text-red-500"
>
Dismiss
</button>
}
>
Content here
</HintTooltip>Size Variants
// Small (max-width: 200px, text-xs)
<HintTooltip size="sm" {...props}>Brief tip</HintTooltip>
// Default (max-width: 280px, text-sm)
<HintTooltip size="default" {...props}>Standard content</HintTooltip>
// Large (max-width: 360px, text-base)
<HintTooltip size="lg" {...props}>
Detailed explanation with more content
</HintTooltip>Complete Example
Here's a full example combining all components:
import { HintsProvider, Hint, useHint } from '@tour-kit/hints';
function FeatureDiscovery() {
return (
<HintsProvider>
{/* New feature announcement */}
<Hint
id="export-feature"
target="#export-btn"
content="New! Export your data to multiple formats"
color="success"
persist={true}
/>
{/* Important action hint */}
<Hint
id="save-warning"
target="#save-btn"
content="Don't forget to save your changes"
color="warning"
position="bottom-right"
/>
{/* Subtle help hint */}
<Hint
id="help-hint"
target="#help-icon"
content="Click for documentation"
size="sm"
pulse={false}
/>
<Dashboard />
</HintsProvider>
);
}
// Control hints programmatically
function HintControls() {
const exportHint = useHint('export-feature');
return (
<div>
<button onClick={exportHint.show}>Show Hint</button>
<button onClick={exportHint.dismiss}>Dismiss Forever</button>
<button onClick={exportHint.reset}>Reset Hint</button>
<p>Status: {exportHint.isDismissed ? 'Dismissed' : exportHint.isOpen ? 'Open' : 'Hidden'}</p>
</div>
);
}Accessibility
All hint components are built with accessibility in mind:
- Hotspot: Has
role="button",aria-label, andaria-expanded - Tooltip: Has
role="tooltip"via floating-ui - Close button: Has descriptive
aria-label="Dismiss hint" - Keyboard: Escape key dismisses open tooltips
- Focus: Focus ring visible on keyboard navigation
The pulsing animation respects prefers-reduced-motion. Users with motion sensitivity will see a static indicator instead.
Related
- Hooks - useHints and useHint for programmatic control
- Persistence - Configure hint dismissal persistence
- Headless - Build custom hint UI