src/components/ui/Tooltip.astro
---
/**
* Tooltip
* Hover/focus tooltip wrapper. Puur CSS, geen JS nodig.
* Positie: top (default), bottom, left, right.
*/
interface Props {
content: string;
position?: 'top' | 'bottom' | 'left' | 'right';
delay?: boolean;
dark?: boolean;
}
const {
content,
position = 'top',
delay = true,
dark = true,
} = Astro.props;
---
<span
class:list={['tt', `tt--${position}`, { 'tt--delay': delay, 'tt--light': !dark }]}
data-component="tooltip"
data-tip={content}
>
<slot />
<span class="tt__bubble" role="tooltip">{content}</span>
</span>
<style>
.tt {
position: relative;
display: inline-flex;
align-items: center;
}
/* Bubble */
.tt__bubble {
position: absolute;
background: var(--color-primary, #0a0a0a);
color: #fff;
font-size: 0.75rem;
font-weight: 500;
padding: 0.375rem 0.625rem;
border-radius: 0.375rem;
white-space: nowrap;
pointer-events: none;
z-index: 50;
opacity: 0;
transition: opacity 0.15s, transform 0.15s;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
line-height: 1.4;
max-width: 200px;
white-space: normal;
text-align: center;
}
.tt--light .tt__bubble {
background: var(--color-bg, #fff);
color: var(--color-primary, #0a0a0a);
border: 1px solid rgba(0,0,0,0.1);
}
/* Arrow */
.tt__bubble::before {
content: '';
position: absolute;
border: 5px solid transparent;
}
/* Position: top (default) */
.tt--top .tt__bubble {
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%) translateY(4px);
}
.tt--top .tt__bubble::before {
top: 100%;
left: 50%;
transform: translateX(-50%);
border-top-color: var(--color-primary, #0a0a0a);
border-bottom: none;
}
.tt--top.tt--light .tt__bubble::before { border-top-color: rgba(0,0,0,0.1); }
/* Position: bottom */
.tt--bottom .tt__bubble {
top: calc(100% + 8px);
left: 50%;
transform: translateX(-50%) translateY(-4px);
}
.tt--bottom .tt__bubble::before {
bottom: 100%;
left: 50%;
transform: translateX(-50%);
border-bottom-color: var(--color-primary, #0a0a0a);
border-top: none;
}
/* Position: left */
.tt--left .tt__bubble {
right: calc(100% + 8px);
top: 50%;
transform: translateY(-50%) translateX(4px);
}
.tt--left .tt__bubble::before {
left: 100%;
top: 50%;
transform: translateY(-50%);
border-left-color: var(--color-primary, #0a0a0a);
border-right: none;
}
/* Position: right */
.tt--right .tt__bubble {
left: calc(100% + 8px);
top: 50%;
transform: translateY(-50%) translateX(-4px);
}
.tt--right .tt__bubble::before {
right: 100%;
top: 50%;
transform: translateY(-50%);
border-right-color: var(--color-primary, #0a0a0a);
border-left: none;
}
/* Show on hover/focus */
.tt:hover .tt__bubble,
.tt:focus-within .tt__bubble {
opacity: 1;
}
.tt--top:hover .tt__bubble,
.tt--top:focus-within .tt__bubble { transform: translateX(-50%) translateY(0); }
.tt--bottom:hover .tt__bubble,
.tt--bottom:focus-within .tt__bubble { transform: translateX(-50%) translateY(0); }
.tt--left:hover .tt__bubble,
.tt--left:focus-within .tt__bubble { transform: translateY(-50%) translateX(0); }
.tt--right:hover .tt__bubble,
.tt--right:focus-within .tt__bubble { transform: translateY(-50%) translateX(0); }
/* Delay */
.tt--delay .tt__bubble { transition-delay: 0s, 0s; }
.tt--delay:hover .tt__bubble { transition-delay: 0.3s; }
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
content * | string | — | Tooltip tekst |
position | 'top' | 'bottom' | 'left' | 'right' | 'top' | Positie ten opzichte van trigger |
delay | boolean | false | 300ms vertraging voor hover |
* = verplicht