Tooltip
A popup component that displays contextual information when hovering or focusing on a trigger element.
Docsimport { Tooltip, TooltipTrigger, TooltipContent } from "~/components/tooltip";
export default function TooltipBasicDemo() {
return (
<Tooltip>
<TooltipTrigger>Hover me</TooltipTrigger>
<TooltipContent>Tooltip content</TooltipContent>
</Tooltip>
);
}Installation
CLI
Run the following command to add the component to your project:
npx @ark-preset/cli@latest add tooltipManual
Create the recipe file at src/components/recipes/tooltip.ts:
import { tv, type VariantProps } from "tailwind-variants";
export const tooltipVariants = tv({
slots: {
root: "inline-flex",
trigger:
"inline-flex items-center justify-center gap-2 rounded-md border border-input bg-transparent px-4 py-2 text-sm font-medium text-foreground ring-offset-background transition-colors hover:bg-accent max-sm:select-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
positioner: "z-50",
content:
"z-50 overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
arrow: "",
arrowTip: "h-2 w-2 border-t border-l border-border bg-popover",
},
});
export type TooltipVariants = VariantProps<typeof tooltipVariants>;Create the component directory and files.
src/components/tooltip/tooltip.base.tsx:
import { Tooltip as ArkTooltip } from "@ark-ui/solid/tooltip";
import { splitProps, type Component } from "solid-js";
import { buttonVariants, tooltipVariants, type ButtonVariants } from "../recipes/tooltip";
const styles = tooltipVariants();
const Root = ArkTooltip.Root;
const RootProvider = ArkTooltip.RootProvider;
const Trigger: Component<ArkTooltip.TriggerProps & ButtonVariants> = (props) => {
const [local, others] = splitProps(props, ["class", "variant", "size"]);
return (
<ArkTooltip.Trigger
class={buttonVariants({ variant: local.variant, size: local.size, class: local.class })}
{...others}
/>
);
};
const Positioner: Component<ArkTooltip.PositionerProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkTooltip.Positioner class={styles.positioner({ class: local.class })} {...others} />;
};
const Content: Component<ArkTooltip.ContentProps> = (props) => {
const [local, others] = splitProps(props, ["class", "style"]);
return (
<ArkTooltip.Content
class={styles.content({ class: local.class })}
{...others}
style={`--arrow-size: 10px; ${local.style}`}
/>
);
};
const Arrow: Component<ArkTooltip.ArrowProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkTooltip.Arrow class={styles.arrow({ class: local.class })} {...others} />;
};
const ArrowTip: Component<ArkTooltip.ArrowTipProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkTooltip.ArrowTip class={styles.arrowTip({ class: local.class })} {...others} />;
};
export const Tooltip = {
Root,
RootProvider,
Trigger,
Positioner,
Content,
Arrow,
ArrowTip,
};src/components/tooltip/index.tsx:
import { splitProps, type Component } from "solid-js";
import { Tooltip as TooltipBase } from "./tooltip.base";
import { Tooltip as ArkTooltip } from "@ark-ui/solid/tooltip";
const Tooltip = TooltipBase.Root;
const TooltipTrigger = TooltipBase.Trigger;
type TooltipContentProps = ArkTooltip.ContentProps & {
/** When true, renders an arrow pointing to the trigger element */
useArrow?: boolean;
};
const TooltipContent: Component<TooltipContentProps> = (props) => {
const [local, others] = splitProps(props, ["useArrow", "children"]);
return (
<TooltipBase.Positioner>
<TooltipBase.Content {...others}>
{local.useArrow && (
<TooltipBase.Arrow>
<TooltipBase.ArrowTip />
</TooltipBase.Arrow>
)}
{local.children}
</TooltipBase.Content>
</TooltipBase.Positioner>
);
};
export { Tooltip, TooltipTrigger, TooltipContent, TooltipBase };
export { tooltipVariants, type TooltipVariants } from "../recipes/tooltip";Note: Make sure your project has the Tailwind CSS theme variables set up (
--background,--foreground,--ring,--border, etc.) or override the utility classes to match your design system.
Dependencies: This component imports shared recipes or sub-components from other packages. Make sure the following are also installed: button.
Usage
Basic Usage
import { Tooltip, TooltipTrigger, TooltipContent } from "~/components/tooltip";
export default function TooltipBasicDemo() {
return (
<Tooltip>
<TooltipTrigger>Hover me</TooltipTrigger>
<TooltipContent>Tooltip content</TooltipContent>
</Tooltip>
);
}With Arrow
Add an arrow pointing to the trigger element.
import { Tooltip, TooltipTrigger, TooltipContent } from "~/components/tooltip";
export default function TooltipArrowDemo() {
return (
<div class="flex justify-center">
<Tooltip>
<TooltipTrigger>With Arrow</TooltipTrigger>
<TooltipContent useArrow>Tooltip with arrow</TooltipContent>
</Tooltip>
</div>
);
}Controlled Open State
Use open and onOpenChange to control the tooltip visibility externally:
import { createSignal } from "solid-js";
import { Tooltip, TooltipTrigger, TooltipContent } from "~/components/tooltip";
export default function TooltipControlledDemo() {
const [open, setOpen] = createSignal(false);
return (
<div class="flex flex-col items-center gap-4">
<button
class="inline-flex items-center justify-center gap-2 rounded-md border border-input bg-transparent px-4 py-2 text-sm font-medium text-foreground ring-offset-background transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
onClick={() => setOpen((v) => !v)}
>
{open() ? "Close" : "Open"} tooltip
</button>
<Tooltip open={open()} onOpenChange={(e: { open: boolean }) => setOpen(e.open)}>
<TooltipTrigger>Hover or click above</TooltipTrigger>
<TooltipContent>Controlled tooltip</TooltipContent>
</Tooltip>
</div>
);
}Advanced Usage
When the composite Tooltip doesn’t provide enough control, import the raw primitive parts via TooltipBase:
import { TooltipBase } from "~/components/tooltip";Or import directly from the base file:
import { Tooltip } from "~/components/tooltip/tooltip.base";Manual Arrow Composition
For custom arrow styling or positioning, compose the parts manually using TooltipBase:
import { Tooltip, TooltipBase } from "~/components/tooltip";
export default function TooltipManualArrowDemo() {
return (
<div class="flex justify-center">
<Tooltip>
<TooltipBase.Trigger>Manual Arrow</TooltipBase.Trigger>
<TooltipBase.Positioner>
<TooltipBase.Content>
<TooltipBase.Arrow class="[--arrow-size:14px]">
<TooltipBase.ArrowTip />
</TooltipBase.Arrow>
Custom arrow size
</TooltipBase.Content>
</TooltipBase.Positioner>
</Tooltip>
</div>
);
}API Reference
See the Ark UI Tooltip documentation.