YA Tooltip
A tooltip component with native Radix positioning for contextual information
The YaTooltip component displays contextual information when users hover over or focus on an element. It uses Radix UI's native positioning and arrow for robust placement that automatically adjusts to viewport constraints. Built on top of Radix UI's Tooltip primitive for full accessibility support.
Quick Start
pnpm dlx shadcn@latest add @yavendio/ya-tooltipnpx shadcn@latest add @yavendio/ya-tooltipyarn dlx shadcn@latest add @yavendio/ya-tooltipimport { YaTooltip, YaTooltipProvider } from '@/components/ui/ya-tooltip'
export default function Example() {
return (
<YaTooltipProvider>
<YaTooltip content="Add to library">
<button>Hover me</button>
</YaTooltip>
</YaTooltipProvider>
)
}Wrap your application or component tree with YaTooltipProvider to enable tooltips.
Basic Usage
Positions
YaTooltip supports 4 positions: top, bottom, left, and right. The tooltip automatically adjusts when near viewport edges.
<YaTooltip content="Top position" side="top">
<button>Top</button>
</YaTooltip>
<YaTooltip content="Bottom position" side="bottom">
<button>Bottom</button>
</YaTooltip>
<YaTooltip content="Left position" side="left">
<button>Left</button>
</YaTooltip>
<YaTooltip content="Right position" side="right">
<button>Right</button>
</YaTooltip>| Side | Description |
|---|---|
top | Tooltip appears above the trigger (default) |
bottom | Tooltip appears below the trigger |
left | Tooltip appears to the left of the trigger |
right | Tooltip appears to the right of the trigger |
Hide Arrow
Use showArrow={false} to hide the arrow indicator.
<YaTooltip content="No arrow indicator" showArrow={false}>
<button>No Arrow</button>
</YaTooltip>Delay Duration
Control how quickly the tooltip appears:
// Quick appearance (100ms)
<YaTooltip content="Quick tooltip" delayDuration={100}>
<button>Quick</button>
</YaTooltip>
// Delayed appearance (500ms)
<YaTooltip content="Delayed tooltip" delayDuration={500}>
<button>Delayed</button>
</YaTooltip>With Icons
import { Info, HelpCircle, Settings, Bell } from 'lucide-react'
<YaTooltip content="More information about this feature">
<button className="p-2">
<Info className="w-4 h-4" />
</button>
</YaTooltip>
<YaTooltip content="Need help? Click for documentation">
<button className="p-2">
<HelpCircle className="w-4 h-4" />
</button>
</YaTooltip>With YaButton
import { YaButton } from '@/components/ui/ya-button'
<YaTooltip content="Save your changes" side="top">
<YaButton variant="primary">Save</YaButton>
</YaTooltip>
<YaTooltip content="Discard all changes" side="top">
<YaButton variant="secondary">Cancel</YaButton>
</YaTooltip>Controlled Mode
const [open, setOpen] = React.useState(false)
<YaTooltip
content="This tooltip is controlled"
open={open}
onOpenChange={setOpen}
>
<button>Controlled Tooltip</button>
</YaTooltip>Provider Configuration
Configure default settings for all tooltips using YaTooltipProvider:
<YaTooltipProvider
delayDuration={300}
skipDelayDuration={500}
disableHoverableContent={false}
>
{/* All tooltips inside will use these defaults */}
<YaTooltip content="Configured tooltip">
<button>Hover</button>
</YaTooltip>
</YaTooltipProvider>Collision Detection
YaTooltip automatically adjusts its position when the tooltip would overflow the viewport. This is handled natively by Radix UI's positioning engine:
- When near the top edge, it flips to the bottom
- When near the left edge, it shifts right
- The arrow position updates automatically to stay aligned with the trigger
Dark Mode
YaTooltip automatically adapts to dark mode:
| Mode | Background | Text |
|---|---|---|
| Light | Dark (--ya-stone-900) | White |
| Dark | Light (--ya-stone-50) | Black |
Standalone Content
Use YaTooltipContent for standalone tooltip-styled content:
Default Content
With Arrow
import { YaTooltipContent } from '@/components/ui/ya-tooltip'
<YaTooltipContent>Default Content</YaTooltipContent>
<YaTooltipContent showArrow>With Arrow</YaTooltipContent>Props
YaTooltipProvider Props
| Prop | Type | Default | Description |
|---|---|---|---|
delayDuration | number | 200 | Default delay before tooltips appear (ms) |
skipDelayDuration | number | 300 | How long to skip delay after showing a tooltip |
disableHoverableContent | boolean | false | Prevents hovering over the tooltip content |
YaTooltip Props
| Prop | Type | Default | Description |
|---|---|---|---|
content | ReactNode | - | Required. Content to display inside the tooltip |
side | 'top' | 'bottom' | 'left' | 'right' | 'top' | Side of the trigger to place the tooltip |
showArrow | boolean | true | Whether to show the arrow indicator |
delayDuration | number | - | Override provider's delay for this tooltip |
open | boolean | - | Controlled open state |
defaultOpen | boolean | - | Default open state (uncontrolled) |
onOpenChange | (open: boolean) => void | - | Callback when open state changes |
sideOffset | number | 4 | Offset distance from trigger element |
className | string | - | Additional CSS classes |
YaTooltipContent Props
| Prop | Type | Default | Description |
|---|---|---|---|
showArrow | boolean | false | Whether to show the arrow indicator |
className | string | - | Additional CSS classes |
Accessibility
Best Practices
| Do | Don't |
|---|---|
| Keep content concise (1-2 lines) | Long paragraphs or complex content |
| Use for non-essential information | Critical information only in tooltips |
| Quick delay for icon buttons (100-200ms) | Same delay for all tooltip types |
| Provide touch alternatives | Rely solely on hover interactions |
| Let Radix handle collision detection | Manually position tooltips |
TypeScript
import type { TooltipSide, YaTooltipProps } from '@/components/ui/ya-tooltip'
interface MyComponentProps {
tooltipSide?: TooltipSide
}Migration from Previous Version
If you were using the previous arrow prop with 9 positions, here's how to migrate:
Previous arrow | New side |
|---|---|
top-left | side="top" |
top-center | side="top" |
top-right | side="top" |
bottom-left | side="bottom" |
bottom-center | side="bottom" |
bottom-right | side="bottom" |
left | side="left" |
right | side="right" |
none | showArrow={false} |