# Tooltip

Hover-revealed inline guidance with a shared Tailwind-styled surface, role="tooltip", a 500ms pointer delay, and immediate keyboard focus.

- Package: `@mielui/svelte`
- Component version: `2.2.0`
- Depends on Mielui components: _internal/utils
- Shared utilities: components/_internal/theme-changes, transition, components/_internal/surface, utils.cn, utils.createContext

## Install

~~~~sh
pnpm dlx @mielui/svelte add tooltip
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Content

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| class | string \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| surface | "solid" \| "glass" \| undefined | - | No | No | Surface treatment. Omit it to inherit `--mielui-surface` from the theme. |
| rich | boolean \| undefined | false | No | No | Shows the content's markup in the bubble instead of its plain text. |



### Provider

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| delay | number \| undefined | 500 | No | No | Milliseconds the pointer rests on the trigger before the tooltip opens. Keyboard focus opens it at once, and a neighbour opens at once while one is showing. |
| closeDelay | number \| undefined | 100 | No | No | Milliseconds after the pointer leaves before it closes. |
| placement | TooltipPlacement \| undefined | 'top' | No | No | Side of the trigger the tooltip opens on. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Trigger

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| showOnClick | boolean \| undefined | false | No | No | Also shows the tooltip when the trigger is clicked, for touch screens. |
| class | string \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Public types

~~~~ts
import type { DefaultProps } from '@mielui/svelte/utils';
import type { Snippet } from 'svelte';
import Root from './tooltip.svelte';
import Content from './tooltip-content.svelte';
import Provider from './tooltip-provider.svelte';
import Trigger from './tooltip-trigger.svelte';

export type TooltipPlacement = 'top' | 'left' | 'bottom' | 'right';

export type TooltipProps = {
    /**
     * Milliseconds the pointer rests on the trigger before the tooltip opens.
     * Keyboard focus opens it at once, and a neighbour opens at once while one is showing.
     */
    delay?: number;
    /** Milliseconds after the pointer leaves before it closes. */
    closeDelay?: number;
    /** Side of the trigger the tooltip opens on. */
    placement?: TooltipPlacement;
    /** Content rendered inside. */
    children?: Snippet;
};

export type TooltipTriggerProps = {
    /** Also shows the tooltip when the trigger is clicked, for touch screens. */
    showOnClick?: boolean;
} & DefaultProps;

export type TooltipContentProps = DefaultProps & {
    /** Surface treatment. Omit it to inherit `--mielui-surface` from the theme. */
    surface?: 'solid' | 'glass';
    /** Shows the content's markup in the bubble instead of its plain text. */
    rich?: boolean;
};

export type TooltipProviderProps = { children?: Snippet };

export type TooltipState = {
    text: string;
    placement: TooltipPlacement;
    delay: number;
    closeDelay: number;
    className: string;
};

export { Content, Provider, Root, Trigger };
~~~~

## Examples

### Bottom

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import * as Tooltip from '@mielui/svelte/components/tooltip';
</script>

<Tooltip.Root placement="bottom">
    <Tooltip.Trigger>
        <Button variant="outline">Bottom</Button>
    </Tooltip.Trigger>
    <Tooltip.Content>Appears below the trigger</Tooltip.Content>
</Tooltip.Root>
~~~~

### Glass

~~~~svelte
<script lang="ts">
    import {
        FrameIcon as Frame,
        BubbleChatIcon as MessageCircle,
        MousePointer01Icon as MousePointer2,
        PenTool01Icon as PenTool,
        SquareIcon as Square,
        TextFontIcon as Type
    } from '@hugeicons/core-free-icons';
    import { Button } from '@mielui/svelte/components/button';
    import Kbd from '@mielui/svelte/components/kbd';
    import * as Tooltip from '@mielui/svelte/components/tooltip';
    import HugeiconsIcon from '@mielui/svelte/hugeicons-icon';

    let activeTool = $state('move');

    const tools = [
        {
            id: 'move',
            label: 'Move',
            shortcut: 'V',
            icon: MousePointer2
        },
        {
            id: 'frame',
            label: 'Frame',
            shortcut: 'F',
            icon: Frame
        },
        {
            id: 'rectangle',
            label: 'Rectangle',
            shortcut: 'R',
            icon: Square
        },
        {
            id: 'pen',
            label: 'Pen',
            shortcut: 'P',
            icon: PenTool
        },
        {
            id: 'text',
            label: 'Text',
            shortcut: 'T',
            icon: Type
        },
        {
            id: 'comment',
            label: 'Comment',
            shortcut: 'C',
            icon: MessageCircle
        }
    ];
</script>

<div class="flex max-w-full items-center justify-center p-2 sm:p-6">
    <div
        class="flex flex-wrap gap-1 rounded-[calc(var(--radius-control)+var(--spacing)+var(--border-size))] border border-border bg-card p-1 shadow-[var(--elevation-1)]"
    >
        {#each tools as tool (tool.id)}
            <Tooltip.Root placement="top" delay={300}>
                <Tooltip.Trigger>
                    <Button
                        variant="ghost"
                        size="icon"
                        class={activeTool === tool.id
                            ? 'bg-[var(--color-wash)] text-foreground'
                            : 'text-foreground-muted hover:text-foreground'}
                        onclick={() => {
                            activeTool = tool.id;
                        }}
                        aria-label={tool.label}
                        aria-pressed={activeTool === tool.id}
                    >
                        <HugeiconsIcon icon={tool.icon} size={16} />
                    </Button>
                </Tooltip.Trigger>
                <Tooltip.Content surface="glass" rich>
                    <div class="flex items-center gap-2">
                        <span>{tool.label}</span>
                        <Kbd
                            shortcut={tool.shortcut}
                            class="border-transparent bg-[color-mix(in_oklab,var(--color-tooltip-foreground)_16%,transparent)] text-[var(--color-tooltip-foreground)] shadow-none"
                        />
                    </div>
                </Tooltip.Content>
            </Tooltip.Root>
        {/each}
    </div>
</div>
~~~~

### Hero

~~~~svelte
<script lang="ts">
    import {
        FrameIcon as Frame,
        BubbleChatIcon as MessageCircle,
        MousePointer01Icon as MousePointer2,
        PenTool01Icon as PenTool,
        SquareIcon as Square,
        TextFontIcon as Type
    } from '@hugeicons/core-free-icons';
    import { Button } from '@mielui/svelte/components/button';
    import Kbd from '@mielui/svelte/components/kbd';
    import * as Tooltip from '@mielui/svelte/components/tooltip';
    import HugeiconsIcon from '@mielui/svelte/hugeicons-icon';

    let activeTool = $state('move');

    const tools = [
        {
            id: 'move',
            label: 'Move',
            shortcut: 'V',
            icon: MousePointer2
        },
        {
            id: 'frame',
            label: 'Frame',
            shortcut: 'F',
            icon: Frame
        },
        {
            id: 'rectangle',
            label: 'Rectangle',
            shortcut: 'R',
            icon: Square
        },
        {
            id: 'pen',
            label: 'Pen',
            shortcut: 'P',
            icon: PenTool
        },
        {
            id: 'text',
            label: 'Text',
            shortcut: 'T',
            icon: Type
        },
        {
            id: 'comment',
            label: 'Comment',
            shortcut: 'C',
            icon: MessageCircle
        }
    ];
</script>

<div class="flex max-w-full items-center justify-center p-2 sm:p-6">
    <div
        class="flex flex-wrap gap-1 rounded-[calc(var(--radius-control)+var(--spacing)+var(--border-size))] border border-border bg-card p-1 shadow-[var(--elevation-1)]"
    >
        {#each tools as tool (tool.id)}
            <Tooltip.Root placement="top" delay={300}>
                <Tooltip.Trigger>
                    <Button
                        variant="ghost"
                        size="icon"
                        class={activeTool === tool.id
                            ? 'bg-[var(--color-wash)] text-foreground'
                            : 'text-foreground-muted hover:text-foreground'}
                        onclick={() => {
                            activeTool = tool.id;
                        }}
                        aria-label={tool.label}
                        aria-pressed={activeTool === tool.id}
                    >
                        <HugeiconsIcon icon={tool.icon} size={16} />
                    </Button>
                </Tooltip.Trigger>
                <Tooltip.Content rich>
                    <div class="flex items-center gap-2">
                        <span>{tool.label}</span>
                        <Kbd
                            shortcut={tool.shortcut}
                            class="border-transparent bg-[color-mix(in_oklab,var(--color-tooltip-foreground)_16%,transparent)] text-[var(--color-tooltip-foreground)] shadow-none"
                        />
                    </div>
                </Tooltip.Content>
            </Tooltip.Root>
        {/each}
    </div>
</div>
~~~~

### Rich

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import * as Tooltip from '@mielui/svelte/components/tooltip';
</script>

<Tooltip.Provider>
    <Tooltip.Root>
        <Tooltip.Trigger>
            <Button variant="outline">Sync status</Button>
        </Tooltip.Trigger>
        <Tooltip.Content rich>
            <span class="flex items-center gap-2">
                <span aria-hidden="true" class="size-1.5 rounded-full bg-success"></span>
                <span><span class="font-medium">Synced</span> · just now</span>
            </span>
        </Tooltip.Content>
    </Tooltip.Root>
</Tooltip.Provider>
~~~~

### Right

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import * as Tooltip from '@mielui/svelte/components/tooltip';
</script>

<Tooltip.Root placement="right">
    <Tooltip.Trigger>
        <Button variant="outline">Right</Button>
    </Tooltip.Trigger>
    <Tooltip.Content>Appears to the right</Tooltip.Content>
</Tooltip.Root>
~~~~

### Top

~~~~svelte
<script lang="ts">
    import { InformationCircleIcon as Info } from '@hugeicons/core-free-icons';
    import { Button } from '@mielui/svelte/components/button';
    import * as Tooltip from '@mielui/svelte/components/tooltip';
    import HugeiconsIcon from '@mielui/svelte/hugeicons-icon';
</script>

<Tooltip.Root placement="top">
    <Tooltip.Trigger>
        <Button variant="outline">
            <HugeiconsIcon icon={Info} size={14} />
            Top
        </Button>
    </Tooltip.Trigger>
    <Tooltip.Content>Appears above the trigger</Tooltip.Content>
</Tooltip.Root>
~~~~

For the rendered reference, visit [/docs/components/tooltip](/docs/components/tooltip).
