Fluxon.Components.Tooltip (Fluxon v3.0.0)

A small floating label that appears next to a trigger element on hover or keyboard focus.

Tooltip is the right choice for short, non-interactive hints: explaining what an icon button does, expanding a truncated label, or providing a one-line note on a form field. Tooltips position themselves automatically relative to the trigger, flip and shift to stay inside the viewport, and hide when the cursor leaves or the trigger loses focus.

Choosing between tooltip and popover

Reach for tooltip for short, non-interactive labels and hints. The content closes as soon as the user moves away and is not focusable on its own. Reach for Fluxon.Components.Popover when the floating content needs to be focused, scrolled, contain links, or stay open while the user interacts with it.

Usage

The simplest tooltip wraps a trigger element and supplies a one-line label via value:

<.tooltip value="Opens in a new window">
  <.button>Open</.button>
</.tooltip>

For richer content, omit value and use the :content slot:

<.tooltip>
  <.button>View details</.button>
  <:content>
    <div class="space-y-2">
      <img src={~p"/images/preview.png"} class="rounded-lg w-full" />
      <p class="text-sm">Preview of the document layout and structure.</p>
    </div>
  </:content>
</.tooltip>

When both value and :content are provided, value wins.

Placement

The placement attribute hints at the preferred side. The tooltip flips to the opposite side if there is not enough space in the preferred direction, and shifts along the trigger to stay inside the viewport.

PlacementWhen to use
topDefault. Best for triggers in the middle or upper half of the viewport.
bottomTriggers near the top of the viewport, or where a downward tail reads more naturally (toolbars, top nav).
leftTriggers on the right edge of a row, or where the tooltip should not cover content above or below.
rightTriggers on the left edge of a row, or in a sidebar where the tooltip should expand into the main content area.
<div class="flex gap-4">
  <.tooltip value="Opens in a new window" placement="top">
    <.button>Top</.button>
  </.tooltip>

  <.tooltip value="Saves to your profile" placement="right">
    <.button>Right</.button>
  </.tooltip>

  <.tooltip value="Requires permission" placement="bottom">
    <.button>Bottom</.button>
  </.tooltip>
</div>

Trigger Patterns

By default the trigger is the first child of <.tooltip> and the tooltip wrapper renders as display: contents, so the trigger keeps its place in the layout:

<.tooltip value="Share this page">
  <.button variant="ghost"><.icon name="hero-share" /></.button>
</.tooltip>

When the trigger cannot be a direct child (third-party components, complex layouts, multiple triggers sharing one tooltip), pass a CSS selector via target. The tooltip listens for hover and focus on the targeted element and positions itself relative to it instead:

<button id="external-btn" type="button">External Trigger</button>

<.tooltip value="Targets an external element" target="#external-btn">
  <span></span>
</.tooltip>

target selector resolves once

The target selector is resolved on mount; if the matching element is added to the DOM later, the tooltip will not pick it up. Render both the tooltip and its target in the same LiveView render so they mount together.

Hover Delay

Tooltips wait delay milliseconds (default 200) before appearing, so a fast cursor sweep across a row of icons does not flash a tooltip on every one. Once a tooltip has been visible, subsequent tooltips on the page open instantly until 500ms passes with no tooltip visible: this "warmup" makes scanning a toolbar feel responsive after the first interaction without losing the protection against accidental hovers.

Set delay={0} to opt out of the delay entirely:

<.tooltip value="Archived items are hidden from the main view" delay={0}>
  <.icon name="hero-archive" />
</.tooltip>

When the cursor moves from the trigger onto the tooltip itself the tooltip stays open, so rich content that contains links or images can be read without it disappearing mid-hover.

Showing and Dismissing

A tooltip opens when the trigger is hovered or receives keyboard focus, so keyboard users see the same hints as pointer users. Focus that comes from a mouse click does not open the tooltip; only keyboard focus (for example tabbing to the trigger) does. That keeps a click on a button from leaving a tooltip pinned open after the cursor moves away.

A visible tooltip hides when the cursor leaves, when the trigger loses focus, when Escape is pressed (focus stays on the trigger), and when the browser window loses focus (for example after clicking a trigger that opens a link in a new tab). Showing on focus never moves or traps focus.

Customization

Pass a class to override the default background, text color, or width. Use arrow={false} to hide the pointing arrow when the tooltip should read as a flat label:

<.tooltip
  value="Draft saved"
  class="bg-success text-on-success"
  arrow={false}
>
  <.badge>Draft</.badge>
</.tooltip>

Examples

Icon buttons with tooltip labels:

<div class="flex gap-2">
  <.tooltip value="Share">
    <.button variant="ghost"><.icon name="hero-share" /></.button>
  </.tooltip>
  <.tooltip value="Add to favorites">
    <.button variant="ghost"><.icon name="hero-star" /></.button>
  </.tooltip>
  <.tooltip value="More actions">
    <.button variant="ghost"><.icon name="hero-ellipsis-horizontal" /></.button>
  </.tooltip>
</div>

Inline help on a form field via the input's :inner_suffix slot:

<.input type="text" name="api_key" label="API Key">
  <:inner_suffix>
    <.tooltip value="Your API key can be found in the developer settings">
      <.icon name="hero-question-mark-circle" class="text-foreground-softer" />
    </.tooltip>
  </:inner_suffix>
</.input>

Hover preview for a user link:

<.tooltip class="max-w-xs">
  <.link navigate={~p"/users/#{user.id}"}>
    {user.name}
  </.link>
  <:content>
    <div class="space-y-1">
      <p class="font-medium">{user.name}</p>
      <p class="text-sm text-foreground-softer">{user.title}</p>
      <p class="text-sm text-foreground-softer">{user.department}</p>
    </div>
  </:content>
</.tooltip>

Truncated cell label that expands on hover, using a single shared tooltip targeted at the cell:

<td id={"cell-#{row.id}"} class="truncate max-w-[12ch]">
  {row.long_label}
</td>

<.tooltip value={row.long_label} target={"#cell-#{row.id}"}>
  <span></span>
</.tooltip>

Status badge with an explanatory tooltip and no arrow for a flat look:

<.tooltip
  value="This account has not been verified yet"
  placement="right"
  arrow={false}
>
  <.badge color="warning">Unverified</.badge>
</.tooltip>

Summary

Components

Renders a tooltip that appears next to its trigger on hover or keyboard focus.

Components

tooltip(assigns)

Renders a tooltip that appears next to its trigger on hover or keyboard focus.

Wraps the trigger element passed via the inner block (or a separately rendered element referenced by target) and shows the floating tooltip after a short delay. Tooltip content comes from either the value attribute (one-line text) or the :content slot (rich content); when both are provided, value wins.

Attributes

  • id (:string) - Identifier for the tooltip wrapper. Auto-generated when omitted.

  • value (:string) - Plain text content displayed inside the tooltip. The shortest path for one-line labels. For markup, links, images, or any HTML structure, use the :content slot instead. When both are provided, value is rendered and :content is ignored.

    Defaults to nil.

  • class (:any) - Additional CSS classes merged onto the floating tooltip element. Stacked on top of the base background, padding, and shadow styles, so utilities passed here win. Use this to cap the width with max-w-*, swap the background color, or change the text color.

    Defaults to nil.

  • arrow (:boolean) - Renders a small triangular arrow on the tooltip pointing at the trigger. Set to false for a flat label without the pointing tail; useful when the tooltip is offset away from the trigger or styled as a chip rather than a callout.

    Defaults to true.

  • placement (:string) - Preferred side of the trigger to place the tooltip on. The tooltip flips to the opposite side when the preferred side does not fit, and shifts along the trigger to stay inside the viewport.

    • top: Above the trigger. Default; works for most contexts.
    • bottom: Below the trigger. Use when the trigger sits near the top of the viewport (toolbars, top nav) where a tail pointing up reads more naturally.
    • left: To the left of the trigger. Use for triggers on the right edge of a row, or where a vertical tooltip should not cover content above or below.
    • right: To the right of the trigger. Use for triggers in a sidebar or on the left edge of a row, so the tooltip expands into the main content area.

    Defaults to "top". Must be one of "bottom", "left", "top", or "right".

  • delay (:integer) - Delay in milliseconds before the tooltip appears on hover. Prevents brief cursor sweeps over a row of triggers from flashing tooltips on each one. After the first tooltip on the page becomes visible, subsequent tooltips open instantly until 500ms passes with no visible tooltip (a "warmup" effect that makes scanning a toolbar feel responsive). Set to 0 to opt out of the delay entirely.

    Defaults to 200.

  • target (:string) - CSS selector pointing at an external trigger element. When set, the tooltip listens for hover and focus on that element instead of the inner block, positions itself relative to it, and renders the inner block as a placeholder. Use when the trigger cannot be a direct child of the tooltip wrapper (third-party components, complex layouts) or when several markup positions need to share one tooltip definition. The selector is resolved once on mount, so the target must already be in the DOM when the tooltip mounts.

    Defaults to nil.

  • on_open (Phoenix.LiveView.JS) - Phoenix.LiveView.JS commands to run after the tooltip finishes opening (after the enter animation completes).

    Defaults to %Phoenix.LiveView.JS{ops: []}.

  • on_close (Phoenix.LiveView.JS) - Phoenix.LiveView.JS commands to run after the tooltip finishes closing (after the leave animation completes).

    Defaults to %Phoenix.LiveView.JS{ops: []}.

Slots

  • inner_block (required) - The trigger element. The first child of the slot is treated as the trigger; hovering or focusing it shows the tooltip, which positions itself relative to that element. When target is set, the inner block is still required by the component signature; pass an empty <span></span> since the external element referenced by target becomes the effective trigger.

  • content - Rich tooltip content. Used only when value is not set. Accepts arbitrary HEEx, including images, links, and layout. Wrap with a width-constraining class on the <.tooltip> itself (class="max-w-xs") when the content is long.