Skip to content
Navigation

Tooltip

Short supplementary hint on hover or focus. Never the only place essential information lives — for that use inline text or a Popover.

Added 14 October 2026

React

Codecomponents/react/tooltip-demo.tsx
import {Button, Tooltip, TooltipContent, TooltipTrigger} from '@stroeer-labs/design-library/react';
import {CircleHelpIcon} from 'lucide-react';

const sides = ['top', 'right', 'bottom', 'left'] as const;

export function TooltipDemo() {
    return (
        <div className="space-y-6">
            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">Sides</p>
                <div className="flex flex-wrap gap-3">
                    {sides.map((side) => (
                        <Tooltip key={side}>
                            <TooltipTrigger render={<Button variant="outline" />}>{side}</TooltipTrigger>
                            <TooltipContent side={side}>Add to library</TooltipContent>
                        </Tooltip>
                    ))}
                </div>
            </div>
            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">Long content (wraps at max-w-xs)</p>
                <div className="flex flex-wrap gap-3">
                    <Tooltip>
                        <TooltipTrigger render={<Button variant="secondary" />}>Hover me</TooltipTrigger>
                        <TooltipContent>Locked while the campaign is live</TooltipContent>
                    </Tooltip>
                </div>
            </div>
            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">Icon trigger — needs its own aria-label</p>
                <div className="flex flex-wrap gap-3">
                    <Tooltip>
                        <TooltipTrigger render={<Button variant="ghost" size="icon" aria-label="Help" />}>
                            <CircleHelpIcon />
                        </TooltipTrigger>
                        <TooltipContent side="right">Help</TooltipContent>
                    </Tooltip>
                </div>
            </div>
            <div className="space-y-2">
                {/* The canonical supplementary tooltip: the value is already on screen, the tooltip only
                    un-truncates it. Nothing is lost if the tooltip never opens, which is the test for whether
                    a tooltip is the right component at all — see docs/components/tooltip.md. */}
                <p className="text-xs font-medium text-muted-foreground">Truncated value shown in full</p>
                <div className="flex flex-wrap gap-3">
                    <Tooltip>
                        <TooltipTrigger
                            render={<Button variant="ghost" aria-label="Q3 Outdoor Billboard Retargeting — Prague and Central Bohemia" />}
                            className="max-w-40 justify-start truncate"
                        >
                            Q3 Outdoor Billboard Retargeting — Prague and Central Bohemia
                        </TooltipTrigger>
                        <TooltipContent>Q3 Outdoor Billboard Retargeting — Prague and Central Bohemia</TooltipContent>
                    </Tooltip>
                </div>
            </div>
        </div>
    );
}

Angular

Codecomponents/angular/tooltip-demo.ts
import {Component} from '@angular/core';
import {HlmButtonImports, HlmTooltipImports} from '@stroeer-labs/design-library/angular';
import {NgIcon, provideIcons} from '@ng-icons/core';
import {lucideCircleHelp} from '@ng-icons/lucide';

// Mirrors the React tooltip demo. Note the API shape difference documented in the component's
// PARITY NOTE: brain takes the tooltip text as an input on the trigger (`[hlmTooltip]`) rather than as a
// separate content element, and its `position` has no `align` and no logical sides.
@Component({
    selector: 'dl-tooltip-demo',
    standalone: true,
    imports: [HlmTooltipImports, HlmButtonImports, NgIcon],
    providers: [provideIcons({lucideCircleHelp})],
    template: `
        <div class="space-y-6">
            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">Sides</p>
                <div class="flex flex-wrap gap-3">
                    <button hlmBtn variant="outline" hlmTooltip="Add to library" position="top">top</button>
                    <button hlmBtn variant="outline" hlmTooltip="Add to library" position="right">right</button>
                    <button hlmBtn variant="outline" hlmTooltip="Add to library" position="bottom">bottom</button>
                    <button hlmBtn variant="outline" hlmTooltip="Add to library" position="left">left</button>
                </div>
            </div>
            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">Long content (wraps at max-w-xs)</p>
                <div class="flex flex-wrap gap-3">
                    <button hlmBtn variant="secondary" hlmTooltip="Locked while the campaign is live">Hover me</button>
                </div>
            </div>
            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">Icon trigger — needs its own aria-label</p>
                <div class="flex flex-wrap gap-3">
                    <button hlmBtn variant="ghost" size="icon" aria-label="Help" hlmTooltip="Help" position="right">
                        <ng-icon name="lucideCircleHelp" />
                    </button>
                </div>
            </div>
            <div class="space-y-2">
                <!-- The canonical supplementary tooltip: the value is already on screen, the tooltip only
                     un-truncates it. Nothing is lost if it never opens, which is the test for whether a
                     tooltip is the right component at all — see docs/components/tooltip.md. -->
                <p class="text-xs font-medium text-muted-foreground">Truncated value shown in full</p>
                <div class="flex flex-wrap gap-3">
                    <button
                        hlmBtn
                        variant="ghost"
                        class="max-w-40 justify-start truncate"
                        [hlmTooltip]="longName"
                        [attr.aria-label]="longName"
                    >
                        {{ longName }}
                    </button>
                </div>
            </div>
        </div>
    `,
})
export class TooltipDemoComponent {
    protected readonly longName = 'Q3 Outdoor Billboard Retargeting — Prague and Central Bohemia';
}