vue-tippy

repository·main·Indexed 21 days ago

https://github.com/kabbouchi/vue-tippy

A Vue.js 3 wrapper for Tippy.js (version 6.7.1) that provides tooltips, popovers, dropdowns, and menus. It offers three usage patterns: a Vue directive (v-tippy), a Vue component (<tippy />), and a Composition API hook (useTippy). The library includes built-in support for TypeScript, WAI-ARIA accessibility, and various animations such as shift-away, scale, and perspective.

Tokens
11.6K
Snippets
56
Records
65
Agent score
70%

What's inside vue-tippy

  1. Overview of VueTippy features

    main

    VueTippy is a Vue 3 wrapper for the Tippy.js library, providing tooltips, popovers, dropdowns, and menus. It is powered by Popper and offers several key features:

    • Optimized positioning engine: Handles flipping and overflow prevention.
    • Accessibility: WAI-ARIA compliant by default.
    • Customization: Themeable via custom CSS, including extra themes and animations.
    • TypeScript Support: Built-in support for TypeScript.
    • Multiple Usage Patterns: Can be used as a Vue Directive (v-tippy), a Vue Component (<tippy />), or via the Composition API (useTippy()).
  2. Understand the Tippy DOM Structure

    main

    To create custom themes, you need to understand the nested structure of a Tippy element:

    • [data-tippy-root]: The outermost node used by Popper for positioning. Do not apply styles here.
    • .tippy-box: The actual container box.
    • .tippy-content: The node containing your content.

    Optional elements:

    • .tippy-backdrop: Appears if animateFill: true is set.
    • .tippy-arrow: The arrow element (appears if arrow: true).
    <div data-tippy-root>
      <div class="tippy-box" data-placement="top">
        <div class="tippy-backdrop"></div>
        <div class="tippy-arrow"></div>
        <div class="tippy-content">
          My content
        </div>
      </div>
    </div>
  3. Use the v-tippy directive

    main

    You can use the v-tippy directive to attach tooltips to any element. You can pass a configuration object to define multiple properties, or pass a simple string for just the tooltip content.

    If you haven't installed the plugin globally, you must import directive from vue-tippy and register it in your component's directives option.

    <template>
      <!-- Using an object for configuration -->
      <button v-tippy="{ content: 'Hi!' }">Tippy!</button>
      
      <!-- Using a simple string for content -->
      <button v-tippy="'Hello!'">Tippy!</button>
    </template>
    
    <script>
      import { directive } from 'vue-tippy'
    
      export default {
        directives: {
          tippy: directive,
        },
      }
    </script>
  4. Generate static site for hosting

    main

    To create a production-ready static build in the dist/ directory for static hosting, run the generate command. To preview the resulting static application, use the start command.

    yarn generate
    # To preview the generated app:
    yarn start
  5. Configure Tippy via Directive, Component, or Composition API

    main

    You can configure Tippy using three different methods in Vue:

    1. Directive: Pass a props object to v-tippy.
    2. Component: Pass props directly to the <tippy> component.
    3. Composition API: Use the useTippy(target, props) hook.

    All configuration is handled via a props object.

    <!-- Tippy Directive -->
    <button v-tippy="props">Hello</button>
    
    <!-- Tippy Component -->
    <tippy prop1 prop2 ...>
      <button>World!</button>
    </tippy>
    
    // Composition api
    useTippy(target, props)
  6. Style CSS Arrows

    main

    CSS arrows are styled by targeting the .tippy-arrow::before pseudo-element. Because the arrow direction changes based on placement, you must target the placement using the data-placement attribute.

    Implementation:

    /* Top placement */
    .tippy-box[data-theme~='tomato'][data-placement^='top'] > .tippy-arrow::before {
      border-top-color: tomato;
    }
    
    /* Bottom placement */
    .tippy-box[data-theme~='tomato'][data-placement^='bottom'] > .tippy-arrow::before {
      border-bottom-color: tomato;
    }
    
    /* Left placement */
    .tippy-box[data-theme~='tomato'][data-placement^='left'] > .tippy-arrow::before {
      border-left-color: tomato;
    }
    
    /* Right placement */
    .tippy-box[data-theme~='tomato'][data-placement^='right'] > .tippy-arrow::before {
      border-right-color: tomato;
    }
    .tippy-box[data-theme~='tomato'][data-placement^='top'] > .tippy-arrow::before {
      border-top-color: tomato;
    }
  7. Change Arrow Size

    main

    There are two ways to change the size of a Tippy arrow:

    Option 1: transform: scale()

    The simplest method. This works for most standard themes.

    .tippy-box[data-theme~='tomato'] > .tippy-arrow::before {
      transform: scale(1.5);
    }

    Option 2: Pixel increase

    If your theme uses a border (like the light-border theme), transform: scale() will distort the border width. In this case, you must manually adjust the arrow size using pixel values directly in your CSS.

  8. Use the Tippy component

    main

    The <tippy> component wraps a trigger element and displays content. You can provide content in two ways:

    1. Via the content prop.
    2. Via the #content slot.

    If you haven't installed the plugin globally, import Tippy from vue-tippy and register it in your component's components option.

    <template>
      <!-- Using the content prop -->
      <tippy content="Hi!">
        <button>Tippy!</button>
      </tippy>
    
      <!-- Using the #content slot -->
      <tippy>
        <button>Tippy!</button>
    
        <template #content>
          Hi!
        </template>
      </tippy>
    </template>
    
    <script>
      import { Tippy } from 'vue-tippy'
    
      export default {
        components: {
          Tippy,
        },
      }
    </script>
  9. Use CSS animations (e.g. Animate.css) with Tippy

    main

    For complex animations that require @keyframes or external libraries like animate.css, use the onMount and onHidden lifecycle hooks to manually add or remove CSS classes from the tippy box element.

    The tippy box can be accessed via instance.popper.firstElementChild.

    useTippy(target, {
      onMount(instance) {
        const box = instance.popper.firstElementChild
        requestAnimationFrame(() => {
          box.classList.add('animated')
          box.classList.add('wobble')
        })
      },
      onHidden(instance) {
        const box = instance.popper.firstElementChild
        box.classList.remove('animated')
        box.classList.remove('wobble')
      },
    })
  10. Create custom animations

    main

    You can define custom animations by targeting the .tippy-box element with specific data attributes in your CSS:

    1. Use the [data-animation] attribute to specify your custom animation name.
    2. Target the visibility state using [data-state="hidden"] or [data-state="visible"].
    3. (Optional) Target specific placements using attribute selectors like [data-placement^="top"].

    After defining the CSS, pass the custom name to the animation prop.

    /* CSS Definition */
    .tippy-box[data-animation='rotate'][data-state='hidden'] {
      opacity: 0;
      transform: rotate(90deg);
    }
    /* Usage */
    useTippy(target, {
      animation: 'rotate',
    })
  11. Install VueTippy globally as a Vue plugin

    main

    To use VueTippy throughout your application, register it as a plugin in your main entry file. You can import the default export or the plugin named export. You should also import the tippy.js/dist/tippy.css stylesheet to ensure correct styling.

    When calling app.use(VueTippy, options), you can provide an optional configuration object to customize the directive name, component name, singleton component name, and global default props.

    import { createApp } from 'vue'
    import VueTippy from 'vue-tippy'
    // or
    // import { plugin as VueTippy } from 'vue-tippy'
    import 'tippy.js/dist/tippy.css'
    
    const app = createApp({})
    
    app.use(
      VueTippy,
      {
        directive: 'tippy', // => v-tippy
        component: 'tippy', // => <tippy/>
        componentSingleton: 'tippy-singleton', // => <tippy-singleton/>
        defaultProps: {
          placement: 'auto-end',
          allowHTML: true,
        }, // => Global default options
      }
    )
    
    app.mount('#app')