Components Tooltip

Petal Pro is the full SaaS app this is built for

Auth, billing, admin, and Claude Code integration included. One purchase, unlimited projects.

Tooltip

A small label that appears on hover or keyboard focus. Pure CSS, no JavaScript and no dependencies, so it works in live and dead views and renders before LiveView even connects.
Basic

Wrap any trigger. The tooltip opens on hover and on keyboard focus.

Add to library
heex
<.tooltip label="Add to library">
  <.button label="Hover me" color="white" />
</.tooltip>
In a toolbar

Tooltips earn their keep on icon-only controls. Give each <.icon_button> a tooltip so the icon still has a name, and reference the bubble with aria-describedby so screen readers announce it.

Bold (⌘B) Italic (⌘I) Insert link (⌘K)
Last saved 2 minutes ago
heex
<div class="inline-flex items-center gap-1 rounded-lg border border-gray-200 bg-white p-1 shadow-xs dark:border-gray-700 dark:bg-gray-800">
  <.tooltip id="tip-bold" label="Bold (⌘B)">
    <.icon_button size="sm" aria-describedby="tip-bold">
      <.icon name="hero-bold" class="w-4 h-4" />
    </.icon_button>
  </.tooltip>
  <.tooltip label="Italic (⌘I)">
    <.icon_button size="sm">
      <.icon name="hero-italic" class="w-4 h-4" />
    </.icon_button>
  </.tooltip>
  <.tooltip label="Insert link (⌘K)">
    <.icon_button size="sm">
      <.icon name="hero-link" class="w-4 h-4" />
    </.icon_button>
  </.tooltip>
  <div class="mx-1 h-5 w-px bg-gray-200 dark:bg-gray-700"></div>
  <.tooltip placement="bottom">
    <:content>
      Last saved <span class="font-semibold">2 minutes ago</span>
    </:content>
    <.icon_button size="sm">
      <.icon name="hero-check-circle" class="w-4 h-4 text-green-500" />
    </.icon_button>
  </.tooltip>
</div>
Placements

Set which side it appears on with placement: top (default), bottom, left or right.

top bottom left right
heex
<.tooltip :for={side <- ~w(top bottom left right)} placement={side} label={side}>
  <.button size="sm" color="white" label={side} />
</.tooltip>
Rich content

Pass markup instead of a plain label with the :content slot.

Last saved 2 minutes ago
heex
<.tooltip placement="bottom">
  <:content>
    Last saved <span class="font-semibold">2 minutes ago</span>
  </:content>
  <.button label="Status" color="white" />
</.tooltip>
Accessibility

The tooltip opens on keyboard focus as well as hover, and the bubble carries a stable id. For screen readers to announce it, reference that id from the focusable trigger with aria-describedby (as shown in the toolbar above):

heex
          <.tooltip id="save-tip" label="Save (⌘S)">
  <.icon_button aria-describedby="save-tip">
    <.icon name="hero-check" />
  </.icon_button>
</.tooltip>

        
Properties
elixir
          attr :id, :string           # bubble id; autogenerated if not set
attr :label, :string        # tooltip text (or use the :content slot)
attr :placement, :string    # "top" (default) | "bottom" | "left" | "right"
attr :disabled, :boolean    # render the trigger with no tooltip
attr :arrow, :boolean       # show the arrow (default true)
attr :class, :any           # extra classes for the wrapper
attr :content_class, :any   # extra classes for the bubble
attr :rest, :global

slot :inner_block, required: true  # the trigger
slot :content                      # rich content; overrides label