OTTODesign System

Components

Tooltip

A tooltip is a floating, non-actionable information that appears when a user hovers over, focuses, or long-press on an element. You can use a tooltip to add information about the parent element. For the icon button it is used to describe the context or action.

Configurator

LiveTooltip: trigger, accessible name and tooltip text
HTML
<div style="width:100%;min-height:180px;display:flex;align-items:center;justify-content:center"><oc-icon-button-v3 variant="secondary" size="100" icon="copy" oc-aria-label="Kopieren" data-oc-tooltip-v2=""></oc-icon-button-v3></div>

Usage

Anatomy

Teilen
LiveAnatomy
HTML
<oc-icon-button-v3 variant="secondary" size="100" icon="share" oc-aria-label="Teilen"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Teilen</oc-popover-v1></div>

Behavior

Interaction

The tooltip appears on hover, long-press or focus (tab) on the parent element. The tooltip disappears after navigating away from the parent element.

Hover, long-press or focus (Tab) the parent element

The tooltip shows below it

Teilen

Navigate away and it disappears

Liveopen and close interaction
HTML
<p class="demo-label" style="text-align:center">Hover, long-press or focus (Tab) the parent element</p><oc-icon-button-v3 variant="secondary" size="100" icon="share" oc-aria-label="Teilen" data-oc-tooltip-v2></oc-icon-button-v3><p class="demo-label" style="text-align:center">The tooltip shows below it</p><div class="group" style="will-change:transform;align-items:center;min-height:80px;align-self:stretch"><oc-icon-button-v3 variant="secondary" size="100" icon="share" oc-aria-label="Teilen"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Teilen</oc-popover-v1></div><p class="demo-label" style="text-align:center">Navigate away and it disappears</p><oc-icon-button-v3 variant="transparent" size="100" icon="share" oc-aria-label="Teilen"></oc-icon-button-v3></div>

Fitting

The tooltip uses fit-content. If there is not enough space, the content breaks and fills the viewport with 8px distance to the sides. The maximum width of the tooltip is 432px.

fit-content

Kopieren

Breaks at the maximum width, 8px from the viewport edge

Dies ist ein längerer Hinweis: Er bricht um, sobald er die maximale Breite erreicht, und hält immer 8px Abstand zum Rand.
Livefitting
HTML
<p class="demo-label" style="align-self:stretch;text-align:center">fit-content</p><oc-icon-button-v3 variant="secondary" size="100" icon="copy" oc-aria-label="Kopieren"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Kopieren</oc-popover-v1></div>
<p class="demo-label" style="align-self:stretch;text-align:center">Breaks at the maximum width, 8px from the viewport edge</p><oc-icon-button-v3 variant="secondary" size="100" icon="copy" oc-aria-label="Kopieren"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Dies ist ein längerer Hinweis: Er bricht um, sobald er die maximale Breite erreicht, und hält immer 8px Abstand zum Rand.</oc-popover-v1></div>

Placement

By default, the tooltip is positioned centered below the parent element but you can also place it above. In general the position depends on the available space, so it can be aligned to the left, center or right and top or bottom. The tooltip has a spacing of 4px to the parent element.

Bottom (default)

Teilen

Top

Teilen
Livepositioning top or bottom
HTML
<p class="demo-label" style="align-self:stretch;text-align:center">Bottom (default)</p><oc-icon-button-v3 variant="secondary" size="100" icon="share" oc-aria-label="Teilen"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Teilen</oc-popover-v1></div>
<p class="demo-label" style="align-self:stretch;text-align:center">Top</p><oc-icon-button-v3 variant="secondary" size="100" icon="share" oc-aria-label="Teilen"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="top">Teilen</oc-popover-v1></div>

Left

Link zum Artikel kopieren

Center

Link zum Artikel kopieren

Right

Link zum Artikel kopieren
Livealignment left, center or right
HTML
<p class="demo-label" style="align-self:stretch;text-align:center">Left</p><oc-icon-button-v3 variant="secondary" size="100" icon="copy" oc-aria-label="Link zum Artikel kopieren"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Link zum Artikel kopieren</oc-popover-v1></div>
<p class="demo-label" style="align-self:stretch;text-align:center">Center</p><oc-icon-button-v3 variant="secondary" size="100" icon="copy" oc-aria-label="Link zum Artikel kopieren"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Link zum Artikel kopieren</oc-popover-v1></div>
<p class="demo-label" style="align-self:stretch;text-align:center">Right</p><oc-icon-button-v3 variant="secondary" size="100" icon="copy" oc-aria-label="Link zum Artikel kopieren"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">Link zum Artikel kopieren</oc-popover-v1></div>

Tooltips are placed above the canvas and frame (level 2). Therefore the tooltip uses a shadow200. For further information refer to the elevationdocumentation.

Tooltip vs. toggletip

Tooltips provide quick and temporary help or explanations, while toggletips provide more detailed information and must be actively closed. For example, you can use a tooltip to describe the context of an icon button. On the other hand, you can use a toggletip to introduce a new feature.

Tooltip

AR-Ansicht

Toggletip

Neu: AR-Ansicht

Platziere dieses Produkt virtuell in deinem Raum, direkt über die Kamera deines Geräts.

Mehr erfahrenAusprobieren
Livetooltip vs toggletip
HTML
<p class="demo-label" style="align-self:stretch;text-align:center">Tooltip</p><oc-icon-button-v3 variant="secondary" size="100" icon="augmented-reality" oc-aria-label="AR-Ansicht"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="tooltip" visible trigger="none" close-on="none" position="bottom">AR-Ansicht</oc-popover-v1></div>
<p class="demo-label" style="align-self:stretch;text-align:center">Toggletip</p><oc-icon-button-v3 variant="secondary" size="100" icon="augmented-reality" oc-aria-label="AR-Ansicht"></oc-icon-button-v3><oc-popover-v1 anchor="previous-sibling" variant="toggletip" close-button visible close-on="none" position="bottom" oc-aria-label="Neu: AR-Ansicht" style="--min-width:min(21rem, calc(100% - 16px))"><div style="display:flex;gap:12px;align-items:flex-start"><oc-icon-v1 type="question-hint" style="flex:none"></oc-icon-v1><div class="demo-stack gap-8"><p class="oc-headline-100" style="color:inherit">Neu: AR-Ansicht</p><p>Platziere dieses Produkt virtuell in deinem Raum, direkt über die Kamera deines Geräts.</p><div class="demo-row" style="gap:16px"><oc-link-v2 variant="inverted" as-button>Mehr erfahren</oc-link-v2><oc-link-v2 variant="inverted-bold" as-button>Ausprobieren</oc-link-v2></div></div></div></oc-popover-v1></div>

Content Guidelines

Kopieren
DoUse short information describing the parent element.
Mit Klick in die Zwischenablage kopieren und anderswo einfügen
Don'tDescribe other elements or provide unnecessary information.

Accessibility

For information on accessibility, refer to the technical documentation.

Status

Implementation

Live demo

Kopfhörer Studio Pro in Schwarz

Neu im Sortiment

Over-Ear-Kopfhörer mit Noise Cancelling, Schwarz

279,00 €

inkl. MwSt., versandkostenfrei

Lieferung morgen, wenn du bis 14 Uhr bestellst

In den Warenkorb
LiveReal OTTO components, rendered by the OTTO component runtime
HTML
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:32px;align-items:center">
<div style="position:relative">
  <img src="/previews/imagery/samples/otto-product-still/product-headphones.webp" alt="Kopfhörer Studio Pro in Schwarz" style="display:block;width:100%;aspect-ratio:1;object-fit:cover;border-radius:16px">
    <oc-icon-button-v3 variant="secondary-over-color" elevation-level="above" icon="wishlist" oc-aria-label="Merken" data-oc-tooltip-v2></oc-icon-button-v3>
    <oc-icon-button-v3 variant="secondary-over-color" elevation-level="above" icon="share" oc-aria-label="Teilen" data-oc-tooltip-v2></oc-icon-button-v3>
    <oc-icon-button-v3 variant="secondary-over-color" elevation-level="above" icon="augmented-reality" oc-aria-label="In deinem Raum ansehen" data-oc-tooltip-v2="AR-Ansicht"></oc-icon-button-v3>
  <div><p class="oc-copy-75" style="color:#6d6d6d">Neu im Sortiment</p><p class="oc-headline-200">Over-Ear-Kopfhörer mit Noise Cancelling, Schwarz</p></div>
  <div><p class="oc-headline-300">279,00 €</p><p class="oc-copy-75" style="color:#6d6d6d">inkl. MwSt., versandkostenfrei</p></div>
  <oc-divider-v1></oc-divider-v1>
  <div style="display:flex;align-items:center;gap:8px"><oc-icon-v1 type="delivery-24h" style="flex:none"></oc-icon-v1><p class="oc-copy-100">Lieferung morgen, wenn du bis 14 Uhr bestellst</p></div>
    <oc-button-v1 variant="primary" icon-type-left="basket">In den Warenkorb</oc-button-v1>
    <oc-icon-button-v3 variant="secondary" icon="copy" oc-aria-label="Link zum Artikel kopieren" data-oc-tooltip-v2="Link kopieren"></oc-icon-button-v3>

Code

Version Tag Status API
v2 <oc-tooltip-v2> Stable, allowed for generation TooltipV2
v1 <oc-tooltip-v1> Deprecated, NOT allowed for generation TooltipV1

Only the latest version (v2) is allowed for generation. Older versions are kept for reference and are deprecated.

Overview (v2)

Tooltip

Global tooltip that attaches to any element via a data-oc-tooltip-v2 attribute, rather than being used as a component in markup directly.

Default variation
Configuration

Explore all available configuration options in the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the tooltip into your project, make sure you have correctly installed the OTTO components package. Add the data-oc-tooltip-v2 attribute to any element to turn it into a tooltip trigger. No wrapping element or slot is required. Look through the variations page for examples of possible variations, including reading the tooltip text from an aria-label and only showing the tooltip on text overflow.

Info

See the Tooltip UX documentation for detailed user experience guidelines.

Note

If you're currently using the tooltip variant of oc-popover-v1, switch to oc-tooltip-v2 instead. It only needs a single attribute, requires no wrapping element, and derives its text automatically from the trigger's accessible name.

Accessibility

The tooltip comes with a set of built-in accessibility features to ensure a seamless experience for all users.

ARIA attributes

The tooltip's visible content is not read by screen readers directly. Instead, screen readers announce the trigger element's own accessible name (aria-label, aria-labelledby, or its text content). When data-oc-tooltip-v2 is used without an explicit text value, the tooltip text is derived from that same accessible name, so sighted and screen reader users always receive the same information.

Configuration (v2)

Tooltip configuration

Configure the tooltip component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

Migration (v2)

Migration from Tooltip v1 to v2

The oc-tooltip has been updated from oc-tooltip-v1 to oc-tooltip-v2. This migration guide provides step-by-step instructions to update your project to the latest version.

Skip to:

What's new
Attribute-driven

The oc-tooltip-v2 is no longer a wrapping component with slots. It is applied directly to any existing element via the data-oc-tooltip-v2 attribute, providing:

  • No extra wrapping element or shadow DOM around your trigger
  • Automatic tooltip text derived from the trigger's own accessible name (aria-label, aria-labelledby, or text content) when no explicit text is given
  • An opt-in mode that only shows the tooltip when the trigger's text is actually truncated/overflowing
API changes
Changed structure

The oc-tooltip-v2 has transitioned from a wrapping web component with slots to a plain data attribute on the trigger element itself:

<!-- From: -->
<oc-tooltip-v1 position="top">
  <oc-icon-button-v3 icon="copy" oc-aria-label="Kopieren"></oc-icon-button-v3>
  <div slot="tooltip-content">Kopieren</div>
</oc-tooltip-v1>
<!-- To: -->
<oc-icon-button-v3 icon="copy" oc-aria-label="Kopieren" data-oc-tooltip-v2></oc-icon-button-v3>
New attributes

The following attributes have been added in v2:

Attribute Description Notes
data-oc-tooltip-v2 Marks an element as a tooltip trigger and optionally sets the tooltip text Replaces the oc-tooltip-v1 wrapper element
data-oc-tooltip-v2.overflow Only shows the tooltip if the trigger (or a descendant) is truncated/overflowing New capability, not available in v1
Removed attributes

The following attributes have been removed, since positioning is now handled automatically via CSS anchor positioning:

v1 Attribute v2 Equivalent Notes
position none The tooltip position is now calculated automatically based on viewport space
disabled none Remove the data-oc-tooltip-v2 attribute to disable the tooltip entirely
Removed methods

The following methods have been removed:

v1 Method v2 Equivalent Notes
recalcPosition() none Positioning is now recalculated automatically
Removed slots

The following slots have been removed:

v1 Slot v2 Equivalent Notes
default none The trigger element itself is used directly, no wrapper is needed
tooltip-content data-oc-tooltip-v2="…" Pass the tooltip text as the attribute value instead of a slotted element
How to migrate

Remove the oc-tooltip-v1 wrapper and add data-oc-tooltip-v2 directly to the element that should trigger the tooltip. If you don't provide an explicit text value, the tooltip falls back to the trigger's own accessible name.

Migrate a basic tooltip

Replace the wrapper and tooltip-content slot with a data-oc-tooltip-v2 attribute holding the tooltip text.

<!-- From: -->
<oc-tooltip-v1>
  <button>Copy</button>
  <div slot="tooltip-content">Copy to clipboard</div>
</oc-tooltip-v1>
<!-- To: -->
<button data-oc-tooltip-v2="Copy to clipboard">Copy</button>
Migrate a tooltip that reads its text from aria-label

If the tooltip text should match the trigger's aria-label, set data-oc-tooltip-v2 without an explicit value.

<!-- From: -->
<oc-tooltip-v1>
  <oc-icon-button-v3 icon="wishlist" oc-aria-label="Add to wishlist"></oc-icon-button-v3>
  <div slot="tooltip-content">Add to wishlist</div>
</oc-tooltip-v1>
<!-- To: -->
<oc-icon-button-v3
  icon="wishlist"
  oc-aria-label="Add to wishlist"
  data-oc-tooltip-v2
></oc-icon-button-v3>
Migrate a tooltip that should only show on text overflow

Add data-oc-tooltip-v2.overflow alongside data-oc-tooltip-v2 to only show the tooltip when the trigger's text is actually truncated. This has no v1 equivalent.

<!-- To: -->
<button
  style="max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
  data-oc-tooltip-v2
  data-oc-tooltip-v2.overflow
>
  A rather long button label that will get truncated
</button>

API v1 (v1, deprecated, not for generation)

Tooltip v1 API

API: <oc-tooltip-v1> (TooltipV1)

The oc-tooltip-v1 component provides customizable tooltips that can display additional information when hovering over or focusing on an element. It is stylable and supports adjustable positions and custom content.

Attributes / properties
Attribute Type Default Required Description
disabled boolean no If true, tooltip does not activate on hover/focus, only programmatically.
position "top" | "bottom" "bottom" no Sets the tooltip position. Note: The position changes, based on the available space in the viewport.
Slots
Slot Required Description
default yes Specifies the element that triggers the tooltip.
tooltip-content yes Sets the text message that appears in the tooltip.
Example:
<div slot='tooltip-content'>Copy</div>
Events
Event Detail type Description
oc-property-change OcTooltipV1Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
Methods
  • recalcPosition: () => void

    Recalculates the position of the tooltip. This can be useful if the content of the tooltip changes dynamically, or if the position of the trigger element changes.

    Returns: void

    Example:

    const tooltip = document.querySelector("oc-tooltip-v1");
    tooltip.recalcPosition();
    

API v2

Tooltip v2 API

API: <oc-tooltip-v2> (TooltipV2)

Global tooltip that attaches to any element via a data-oc-tooltip-v2 attribute, rather than being used as a component in markup directly.

Events
Event Detail type Description
oc-property-change OcTooltipV2Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
CSS custom properties
Custom property Default Description
--anchor Internal CSS anchor-positioning name linking the tooltip to its trigger element.

Variations (v2)

Variations

Listed below are the most common variations of the tooltip component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-tooltip-variations--default · tags: components

Default usage: an explicit data-oc-tooltip-v2="..." value is used as the tooltip text.

Args: data-oc-tooltip-v2=This is the tooltip text

Use Aria Label

Story: components-tooltip-variations--use-aria-label · tags: components

When data-oc-tooltip-v2 is set without an explicit text value, the tooltip falls back to the element's computed accessible name (here via aria-label).

Args: aria-label=Info Icon, contents=["(i)", "(ii)", "(iii)"]

Read From Content

Story: components-tooltip-variations--read-from-content · tags: components

When data-oc-tooltip-v2 is set to an empty string (no explicit text and no aria-label), the tooltip falls back to reading the element's own text content as its accessible name.

Args: data-oc-tooltip-v2=``

Overflow

Story: components-tooltip-variations--overflow · tags: components

data-oc-tooltip-v2.overflow only shows the tooltip when the trigger's text is actually truncated. Resize the demo box to see the tooltip appear once the text overflows.

<button
  data-oc-tooltip-v2
  data-oc-tooltip-v2.overflow
  class="demo-overflow"
  style="width: fit-content"
>
  A short button label. No tooltip needed.
</button>
<button
  data-oc-tooltip-v2
  data-oc-tooltip-v2.overflow
  class="demo-overflow"
  style="width: 50%"
>
  A rather long button label that will get truncated. A rather long button label that will get
  truncated. A rather long button label that will get truncated. A rather long button label
  that will get truncated. Tooltip needed.
</button>
<style>
  .demo-overflow {
    display: block;
    padding: 16px;
    overflow: hidden;
    text-overflow: ellipsis;
    user-select: none;
    white-space: nowrap;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Overflow",
  render() {
    return html`
      <button
        data-oc-tooltip-v2
        data-oc-tooltip-v2.overflow
        class="demo-overflow"
        style="width: fit-content"
      >
        A short button label. No tooltip needed.
      </button>
      <button
        data-oc-tooltip-v2
        data-oc-tooltip-v2.overflow
        class="demo-overflow"
        style="width: 50%"
      >
        A rather long button label that will get truncated. A rather long button label that will get
        truncated. A rather long button label that will get truncated. A rather long button label
        that will get truncated. Tooltip needed.
      </button>
      <style>
        .demo-overflow {
          display: block;
          padding: 16px;
          overflow: hidden;
          text-overflow: ellipsis;
          user-select: none;
          white-space: nowrap;
        }
      </style>
    `;
  }
}

Interaction tests (TooltipV2.interactions.stories.ts)

Interaction test stories (automated tests, not usage patterns).

Open Tooltip on Hover

Story: components-tooltip-interaction-tests--open-tooltip-on-hover · tags: play-fn

<button data-oc-tooltip-v2="Dieser Text sollte kopiert werden">Copy</button>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Open Tooltip on Hover",
  render() {
    return html`<button data-oc-tooltip-v2="Dieser Text sollte kopiert werden">Copy</button>`;
  },
  play: async ({
    canvasElement
  }) => {
    const trigger = canvasElement.querySelector("button")!;
    await userEvent.hover(trigger);
    await waitFor("tooltip visible", async () => {
      await expect(document.querySelector("oc-tooltip-v2")).toBeVisible();
    });
  }
}

Open Tooltip on Focus

Story: components-tooltip-interaction-tests--open-tooltip-on-focus · tags: play-fn

<button data-oc-tooltip-v2="Dieser Text sollte kopiert werden">Copy</button>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Open Tooltip on Focus",
  render() {
    return html`<button data-oc-tooltip-v2="Dieser Text sollte kopiert werden">Copy</button>`;
  },
  play: async ({
    canvasElement
  }) => {
    const trigger = canvasElement.querySelector("button")!;
    trigger.focus();
    await waitFor("trigger has focus", async () => {
      await expect(trigger).toHaveFocus();
    });
    await waitFor("tooltip visible", async () => {
      await expect(document.querySelector("oc-tooltip-v2")).toBeVisible();
    });
  }
}

Close Tooltip on Blur

Story: components-tooltip-interaction-tests--close-tooltip-on-blur · tags: play-fn

<button data-oc-tooltip-v2="Dieser Text sollte kopiert werden">Copy</button>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Close Tooltip on Blur",
  render() {
    return html`<button data-oc-tooltip-v2="Dieser Text sollte kopiert werden">Copy</button>`;
  },
  play: async ({
    canvasElement
  }) => {
    const trigger = canvasElement.querySelector("button")!;
    trigger.focus();
    await waitFor("tooltip visible", async () => {
      await expect(document.querySelector("oc-tooltip-v2")).toBeVisible();
    });
    trigger.blur();
    await macrotasks(100);
    await waitFor("tooltip removed", async () => {
      await expect(document.querySelector("oc-tooltip-v2")).not.toBeInTheDocument();
    });
  }
}

Overflow Gate Only Shows When Truncated

Story: components-tooltip-interaction-tests--shows-only-when-overflowing · tags: play-fn

<button
  data-oc-tooltip-v2
  data-oc-tooltip-v2.overflow
  style="display:block; max-width: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
>
  A rather long button label that will get truncated
</button>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Overflow Gate Only Shows When Truncated",
  render() {
    return html`
      <button
        data-oc-tooltip-v2
        data-oc-tooltip-v2.overflow
        style="display:block; max-width: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
      >
        A rather long button label that will get truncated
      </button>
    `;
  },
  play: async ({
    canvasElement
  }) => {
    const trigger = canvasElement.querySelector("button")!;
    await userEvent.hover(trigger);
    await waitFor("tooltip visible", async () => {
      await expect(document.querySelector("oc-tooltip-v2")).toBeVisible();
    });
  }
}

V1 (v1, deprecated, not for generation)

Tooltip

The tooltip component provides customizable tooltips that can display additional information when hovering over or focusing on an element. It is stylable and supports adjustable positions and custom content.

Default variation
<oc-tooltip-v1 position="top">
  <div slot='tooltip-content'>Kopieren</div>
  <oc-icon-button-v3 icon='copy' oc-aria-label='Kopieren'></oc-icon-button-v3>
</oc-tooltip-v1>
Configuration

The tooltip is configurable, allowing you to tailor its features and appearance to your specific needs. To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the tooltip component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.

Info

See the Tooltip UX documentation for detailed user experience guidelines.

Accessibility

The tooltip component comes with a set of built-in accessibility features to ensure a seamless experience for all users.

ARIA attributes

The tooltip component itself does not need to be made accessible via aria-attributes, because its content cannot be accessed directly by screenreaders, it is just a visual element. It encloses an interactive main element such as a button or a link and an element that provides the tooltip content. Screenreaders can announce either the content of this main element that activates the tooltip, or the value that its aria-attribute holds.

To ensure clarity and accessibility, it's best practice to keep the information in the aria-label attribute of the interactive main element consistent with the tooltip-content of the tooltip, as only the main element is announced by screen readers.

Here's an example:

<!-- The Tooltip wrapper -->
<oc-tooltip-v1 position="top">
  <!-- The interactive main element holding info via `oc-aria-label` that is announced by screen readers -->
  <oc-icon-button-v3 icon="copy" oc-aria-label="Kopieren"></oc-icon-button-v3>
  <!-- The content of the Tooltip-->
  <div slot="tooltip-content">Kopieren</div>
</oc-tooltip-v1>
Keyboard navigation
Shortcut Description
Tab Focuses the interactive main element and opens tooltip
Esc Closes the tooltip when open
Blur/Unfocus Closes the tooltip after a short delay

The tooltip closes after a short delay when the focus is removed.

V1/Configuration (v1, deprecated, not for generation)

Tooltip configuration

Configure the tooltip component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

<oc-tooltip-v1 position="top">
  <div slot='tooltip-content'>Kopieren</div>
  <oc-icon-button-v3 icon='copy' oc-aria-label='Kopieren'></oc-icon-button-v3>
</oc-tooltip-v1>

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

V1/Interaction tests (TooltipV1.interactions.stories.ts)

Interaction test stories (automated tests, not usage patterns).

Open Tooltip on Hover

Story: components-tooltip-v1-interaction-tests--open-tooltip-on-hover · tags: play-fn

Args: defaultSlot=<oc-icon-button-v3 icon='copy' oc-aria-label='Dieser Text sollte kopiert werden'></oc-icon-button-v3> , tooltipContentSlot=<div slot='tooltip-content'>Dieser Text sollte kopiert werden</div> , position=bottom

Story source (TypeScript, verbatim from Storybook)
{
  name: "Open Tooltip on Hover",
  args: {
    defaultSlot: "<oc-icon-button-v3 icon='copy' oc-aria-label='Dieser Text sollte kopiert werden'></oc-icon-button-v3> ",
    tooltipContentSlot: `<div slot='tooltip-content'>Dieser Text sollte kopiert werden</div>
    `,
    position: "bottom"
  },
  play: async ({
    canvasElement
  }) => {
    const tooltipElement = canvasElement.getElementsByTagName("oc-tooltip-v1")[0]!;
    const tooltipActivator = tooltipElement?.querySelector("oc-icon-button-v3");
    await userEvent.hover(tooltipActivator as Element);
    await waitFor("tooltip visible", async () => {
      await expect(tooltipElement.shadowRoot?.querySelector("oc-popover-v1")?.shadowRoot?.querySelector(".popover-popover")).toHaveClass("visible");
    });
  }
}

Open Tooltip on Focus

Story: components-tooltip-v1-interaction-tests--open-tooltip-on-focus · tags: play-fn

Args: defaultSlot=<oc-icon-button-v3 icon='copy' oc-aria-label='Dieser Text sollte kopiert werden'></oc-icon-button-v3> , tooltipContentSlot=<div slot='tooltip-content'><div slot='tooltip-content'>Dieser Text sollte kopiert werden</div></div> , position=bottom

Story source (TypeScript, verbatim from Storybook)
{
  name: "Open Tooltip on Focus",
  args: {
    defaultSlot: "<oc-icon-button-v3 icon='copy' oc-aria-label='Dieser Text sollte kopiert werden'></oc-icon-button-v3> ",
    tooltipContentSlot: `<div slot='tooltip-content'><div slot='tooltip-content'>Dieser Text sollte kopiert werden</div></div>
    `,
    position: "bottom"
  },
  play: async ({
    canvasElement
  }) => {
    const tooltipElement = canvasElement.getElementsByTagName("oc-tooltip-v1")[0]!;
    const tooltipActivator = tooltipElement.querySelector("oc-icon-button-v3")!;
    tooltipActivator.focus();
    await waitFor("tooltip has focus", async () => {
      await expect(tooltipActivator).toHaveFocus();
    });
    await waitFor("tooltip visible", async () => {
      await expect(tooltipElement.shadowRoot?.querySelector("oc-popover-v1")?.shadowRoot?.querySelector(".popover-popover")).toHaveClass("visible");
    });
  }
}

V1/Variations (v1, deprecated, not for generation)

Variations

Listed below are the most common variations of the tooltip component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-tooltip-v1-variations--default · tags: components

The default configuration uses an in the default slot and position=top.

Args: defaultSlot=<oc-icon-button-v3 icon='copy' oc-aria-label='Kopieren'></oc-icon-button-v3> , tooltipContentSlot=<div slot='tooltip-content'>Kopieren</div>, position=top

<oc-tooltip-v1 position="top">
  <div slot='tooltip-content'>Kopieren</div>
  <oc-icon-button-v3 icon='copy' oc-aria-label='Kopieren'></oc-icon-button-v3>
</oc-tooltip-v1>
Demo: different content, positions, and styles

Story: components-tooltip-v1-variations--demo · tags: components

A demo of the tooltip component with different content, positions, and styles.

<style>
  .parent {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 40px;
    justify-items: start;
    align-items: center;
  }
</style>
<br />
<div class="parent">
  <oc-tooltip-v1
    ><oc-icon-button-v3
      icon="info"
      oc-aria-label="Weitere Informationen."
    ></oc-icon-button-v3>
    <div slot="tooltip-content">Weitere Informationen.</div>
  </oc-tooltip-v1>
  <oc-tooltip-v1 position="top"
    ><oc-icon-button-v3
      icon="fitness"
      oc-aria-label="Der Tooltip content kann gestyled werden."
    ></oc-icon-button-v3>
    <div slot="tooltip-content">
      Der <i>Content</i> im <span style="font-weight: bold">Tooltip</span> kann
      <span style="color: red">gestyled</span> werden!
    </div>
  </oc-tooltip-v1>
  <oc-tooltip-v1 position="top">
    <div
      style="display: flex; align-items: center; color: var(--oc-semantic-color-text-interactive)"
    >
      <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
      <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
      <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
      <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
      <oc-icon-v1 type="rating-half" size="100"></oc-icon-v1>
      (1337)
    </div>
    <div slot="tooltip-content">
      4.5 von 5 Sternen (1337 Bewertungen) <br />
      <span>90% Positiv</span>
    </div>
  </oc-tooltip-v1>
  <oc-tooltip-v1
    ><div style="border: 1px dashed green">Multiline<br />Content</div>
    <div slot="tooltip-content">Weitere Informationen.</div>
  </oc-tooltip-v1>
  <oc-tooltip-v1 position="top"
    ><div style="border: 1px dashed green">
      Very long multiline<br />content lorem ipsum dolor sit amet.
    </div>
    <div slot="tooltip-content">Weitere Informationen.</div>
  </oc-tooltip-v1>
</div>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: different content, positions, and styles",
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    },
    docs: {
      story: {
        inline: false,
        iframeHeight: "200px"
      }
    }
  },
  render() {
    return html`
      <style>
        .parent {
          display: flex;
          flex-direction: row;
          flex-wrap: wrap;
          gap: 40px;
          justify-items: start;
          align-items: center;
        }
      </style>
      <br />
      <div class="parent">
        <oc-tooltip-v1
          ><oc-icon-button-v3
            icon="info"
            oc-aria-label="Weitere Informationen."
          ></oc-icon-button-v3>
          <div slot="tooltip-content">Weitere Informationen.</div>
        </oc-tooltip-v1>
        <oc-tooltip-v1 position="top"
          ><oc-icon-button-v3
            icon="fitness"
            oc-aria-label="Der Tooltip content kann gestyled werden."
          ></oc-icon-button-v3>
          <div slot="tooltip-content">
            Der <i>Content</i> im <span style="font-weight: bold">Tooltip</span> kann
            <span style="color: red">gestyled</span> werden!
          </div>
        </oc-tooltip-v1>
        <oc-tooltip-v1 position="top">
          <div
            style="display: flex; align-items: center; color: var(--oc-semantic-color-text-interactive)"
          >
            <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
            <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
            <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
            <oc-icon-v1 type="rating-filled" size="100"></oc-icon-v1>
            <oc-icon-v1 type="rating-half" size="100"></oc-icon-v1>
            (1337)
          </div>
          <div slot="tooltip-content">
            4.5 von 5 Sternen (1337 Bewertungen) <br />
            <span>90% Positiv</span>
          </div>
        </oc-tooltip-v1>
        <oc-tooltip-v1
          ><div style="border: 1px dashed green">Multiline<br />Content</div>
          <div slot="tooltip-content">Weitere Informationen.</div>
        </oc-tooltip-v1>
        <oc-tooltip-v1 position="top"
          ><div style="border: 1px dashed green">
            Very long multiline<br />content lorem ipsum dolor sit amet.
          </div>
          <div slot="tooltip-content">Weitere Informationen.</div>
        </oc-tooltip-v1>
      </div>
    `;
  }
}