# How to Create Custom Tooltips and Popovers Using Element UI Components

> Learn to create custom tooltips and popovers in Element UI using the popper mixin, popperClass prop, and v-model bindings for custom styling and control.

- Repository: [饿了么前端/element](https://github.com/ElemeFE/element)
- Tags: how-to-guide
- Published: 2026-03-07

---

**You create custom tooltips and popovers in Element UI by leveraging the shared Vue-popper mixin, applying CSS classes via the `popperClass` prop, and controlling visibility through trigger configurations or manual `v-model` bindings.**

Element UI provides robust Tooltip and Popover components for displaying contextual information in Vue.js applications. Both components are thin wrappers around the `vue-popper` utility (`element-ui/src/utils/vue-popper`), sharing the same positioning engine while offering distinct APIs for simple text hints versus rich content panels. This guide demonstrates how to create custom tooltips and popovers by examining the source code architecture from the ElemeFE/element repository.

## Understanding the Shared Vue-Popper Architecture

Both **Tooltip** and **Popover** components import the `Popper` mixin from `element-ui/src/utils/vue-popper`, which injects core positioning logic, the `updatePopper()` method, and the reactive `showPopper` flag that drives visibility transitions.

| Aspect | Tooltip | Popover |
|--------|---------|---------|
| Core file | [`packages/tooltip/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/tooltip/src/main.js) | [`packages/popover/src/main.vue`](https://github.com/ElemeFE/element/blob/main/packages/popover/src/main.vue) |
| Render strategy | Render function building `<transition>` → `<div role="tooltip">` | Template rendering `<transition>` → `<div role="tooltip" class="el-popover">` |
| Reference detection | `getFirstElement()` extracts first child from default slot | `reference` prop, named `reference` slot, or first child |
| Default triggers | `mouseenter` / `mouseleave` | Configurable via `trigger` prop: `click`, `hover`, `focus`, `manual` |

According to the ElemeFE/element source code, Tooltip implements event listeners in its `mounted()` hook (lines 14-30), while Popover attaches listeners based on the `trigger` configuration in its own `mounted()` method (lines 17-36).

## Customizing Appearance with CSS Classes and Transitions

Both components expose `popperClass` and `transition` props to customize the popper element's styling and animation. In Tooltip, `popperClass` is applied alongside `el-tooltip__popper` and effect classes in the render logic (line 27), while Popover accepts the same prop to append classes to its root element (line 55).

```html
<el-tooltip content="Styled tooltip" popper-class="my-custom-tooltip" placement="bottom">
  <el-button>Custom Styled</el-button>
</el-tooltip>

<style>
.my-custom-tooltip {
  background: #333;
  color: #fff;
  border-radius: 4px;
}
</style>

```

The `transition` prop (Tooltip lines 32-34, Popover lines 64-66) accepts animation names to customize the show/hide behavior, as both components wrap content in `<transition>` elements.

## Creating Rich HTML Content

**Tooltip** supports multi-line HTML through the `content` slot, overriding the `content` prop to allow arbitrary markup:

```html
<el-tooltip placement="top" effect="light">
  <div slot="content">
    Multi-line information<br/>
    Second line of text
  </div>
  <el-button>Hover me</el-button>
</el-tooltip>

```

**Popover** extends this capability with a dedicated `title` prop and structured slots for complex layouts:

```html
<el-popover trigger="click" title="提示标题" width="200" placement="right" v-model="show">
  <p>Arbitrary HTML content can go here.</p>
  <el-button slot="reference">Open Popover</el-button>
</el-popover>

```

The `reference` slot explicitly defines the trigger element, offering more flexibility than Tooltip's automatic first-element detection via `getFirstElement()` (lines 14-24 in [`main.js`](https://github.com/ElemeFE/element/blob/main/main.js)).

## Controlling Visibility and Triggers

**Manual control** disables automatic event listeners, allowing programmatic management via the `showPopper` internal state:

```html
<template>
  <el-tooltip :manual="true" v-model="visible" content="Controlled tooltip">
    <el-button @click="visible = !visible">Toggle tooltip</el-button>
  </el-tooltip>
</template>

<script>
export default {
  data() {
    return { visible: false };
  }
};
</script>

```

**Trigger delays** prevent accidental activation using `openDelay` and `closeDelay` props. In Popover, these control timers within `handleMouseEnter` and `handleMouseLeave` methods (lines 68-90 in [`main.vue`](https://github.com/ElemeFE/element/blob/main/main.vue)):

```html
<el-popover trigger="hover" open-delay="300" close-delay="200" v-model="visible" placement="bottom">
  <p>Hover-delayed content</p>
  <el-button slot="reference">Hover me</el-button>
</el-popover>

```

For click-triggered popovers, the component automatically handles outside clicks via `handleDocumentClick` to close the popover when clicking elsewhere.

## Working with Reference Elements

Tooltip automatically detects its reference element by extracting the first element from the default slot using `getFirstElement()`. Popover provides three methods for reference specification:

1.  **`reference` prop**: Pass a DOM element or selector
2.  **`reference` slot**: Explicitly define the trigger element in the template
3.  **Default slot**: First child element (fallback behavior)

This architecture is initialized in Popover's `mounted()` hook (lines 88-99 in [`main.vue`](https://github.com/ElemeFE/element/blob/main/main.vue)), ensuring reliable event listener attachment regardless of how the reference is specified.

## Accessibility Implementation

Both components implement ARIA best practices according to the source code. Tooltip adds `aria-describedby` and `tabindex` attributes to reference elements, while Popover adds the same attributes plus `tabindex="0"` on the popover element itself, ensuring full keyboard navigability and screen reader compatibility.

## Summary

- **Shared foundation**: Both components use the `Popper` mixin from [`src/utils/vue-popper.js`](https://github.com/ElemeFE/element/blob/main/src/utils/vue-popper.js) for positioning and the `showPopper` reactive flag.
- **Styling customization**: Apply the `popperClass` prop to inject custom CSS classes into the generated popper DOM element.
- **Content flexibility**: Use the `content` slot in Tooltip for HTML, and the `title` prop plus default slot in Popover for structured panels.
- **Visibility control**: Configure `trigger` types in Popover, or use `manual` mode with `v-model` in both components for programmatic control.
- **Timing control**: Implement `openDelay` and `closeDelay` to prevent accidental triggering, managed internally by mouse event handlers.
- **Reference handling**: Use explicit `reference` slots in Popover for complex layouts, or rely on Tooltip's automatic first-element detection.

## Frequently Asked Questions

### How do I apply custom CSS to a tooltip or popover?

Use the `popper-class` (or `popperClass`) prop to add custom CSS classes to the popper element. This class is appended to the default classes (`el-tooltip__popper` or `el-popover`) in the rendered output, allowing you to override background colors, borders, and shadows as implemented in [`packages/tooltip/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/tooltip/src/main.js) and [`packages/popover/src/main.vue`](https://github.com/ElemeFE/element/blob/main/packages/popover/src/main.vue).

### What is the difference between Tooltip and Popover in Element UI?

**Tooltip** is optimized for simple text hints, automatically detecting its trigger from the default slot and defaulting to hover behavior. **Popover** functions as an enhanced Tooltip with support for titles, explicit `reference` slots, multiple trigger types (click, hover, focus), and width constraints. Both share the same underlying positioning logic from [`src/utils/vue-popper.js`](https://github.com/ElemeFE/element/blob/main/src/utils/vue-popper.js), but Popover offers greater flexibility for interactive content panels.

### How can I programmatically control tooltip visibility?

Set the `manual` prop to `true` and bind the `v-model` directive to a boolean data property. This disables the default mouse listeners defined in the `mounted()` hook (lines 14-30) and allows direct toggling of the internal `showPopper` state, giving you complete control over visibility timing.

### Why does my popover close immediately after opening?

Ensure you are not binding the same `v-model` variable to multiple popovers or conflicting trigger conditions. When using `trigger="click"`, the component uses `handleDocumentClick` to detect outside clicks; verify that your click target is not being detached or that you are not programmatically setting visibility to `false` in conflicting event handlers.