# Popover

API

The Popover-component has a dedicated API documentation.

# Installation

$ npm install @vue-cdk/popover --save

# Usage

@vue-cdk/popover exposes a Vue plugin that you can use like this:

import Vue from 'vue'
import Popover from '@vue-cdk/popover'

Vue.use(Popover)

This will globally register the following components:

  • CPopover: Use this component to specify how a popover should be rendered. Some of the available props are:
    • withArrow: If set to true, the popover will also render an arrow.
    • theme: Set a theme for your popover. You can create custom themes.
    • placement: How to place the actual popover.
  • CPopoverContent: Use this component to specify what the popover should render. You use this component within CPopover. The element/component wrapped with CPopoverContent will appear inside the popover.
  • CPopoverArrow: Use this component to customize the arrow. You usually do not need this component since the arrow can be customized by several props and themes. If you need to render a custom arrow use this component inside the arrow-slot of CPopoverContent.

# Guide

WARNING

Some features of CPopover have been removed temporary. Currently those features are not possible with the latest release of Poppver.JS. The features will be added back once Popper.JS supports those features again.

In a typical scenario you would have some kind of trigger–element (a button, a link, …) that, when clicked will toggle the popover. CPopover expects you to render such a trigger yourself.

The following example shows how to render a button that toggles the visibility of a popover.

Show Code
<template>
  <div>
    <button ref="button" @click="toggle">Toggle</button>

    <CPopover
      placement="bottom"
      :target="() => $refs.button"
      :visible="visible"
      theme="clean"
      with-arrow
    >
      <CPopoverContent> Popover Body </CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'

export default {
  data() {
    return {
      visible: false,
    }
  },
  methods: {
    toggle() {
      this.visible = !this.visible
    },
  },
}
</script>

You can omit theme (or set it to null) to disable all styling.

CSS Required

Themes only work with the corresponding styles. You can import individual themes or all themes by importing @vue-cdk/popover/themes/index.css.

# Examples

# Hello World

This is the a classical Hello World example. You control the visibility of the popover by simply setting visible to true or false. You have to tell CPopover where it should attach itself to. This is done by using trigger and setting it to $refs.button. By doing so CPopover will search for a ref called button.

Show Code
<template>
  <div>
    <button ref="button" @click="toggle">Toggle</button>

    <CPopover
      placement="bottom"
      :target="() => $refs.button"
      :visible="visible"
      theme="clean"
      with-arrow
    >
      <CPopoverContent> Popover Body </CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'

export default {
  data() {
    return {
      visible: false,
    }
  },
  methods: {
    toggle() {
      this.visible = !this.visible
    },
  },
}
</script>

# Manually showing the Popover

Instead of using the visible–prop to show and/or hide the popover you can manually change the visibility. You get a reference to the popover and call its methods (show()/hide()/toggle()) directly.

Show Code
<template>
  <div>
    <button ref="button" @click="$refs.popover.toggle()">Toggle</button>
    <CPopover
      ref="popover"
      with-arrow
      placement="bottom"
      :target="() => $refs.button"
      theme="clean"
    >
      <CPopoverContent> This is a popover. Yay! </CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'
export default {}
</script>

TIP

The example above is not using any theme or custom styles. For this reason it looks like a bit boring. Most of the following examples are using a theme.

# Automatically Hide the Popover

You can combine CPopover with @vue-cdk/interaction-outside to automatically hide the popover when clicks outside of it are detected.

Show Code
<template>
  <div>
    <button ref="button" @click="toggle">Toggle</button>

    <CPopover
      placement="bottom"
      :target="() => $refs.button"
      :visible="visible"
      theme="clean"
      with-arrow
    >
      <CPopoverContent>
        <CInteractionOutside @detected="visible = false">
          <div class="inside">Try to click outside</div>
        </CInteractionOutside>
      </CPopoverContent>
    </CPopover>
  </div>
</template>
<script>
export default {
  data() {
    return {
      visible: false,
    }
  },
  methods: {
    toggle() {
      this.visible = !this.visible
    },
  },
}
</script>

You can also use this for more complex scenarios:

Show Code
<template>
  <div>
    <input
      ref="input"
      v-model="text"
      @keydown.tab="hide"
      @keyup.enter="hide"
      @keyup.esc="hide"
      @focus="show"
      @click="show"
    />
    <input style="width: 200px" value="Focus this by pressing tab" />
    <CPopover
      placement="bottom"
      :target="() => $refs.input"
      :visible="visible"
      theme="clean"
      with-arrow
    >
      <CPopoverContent>
        <CInteractionOutside :ignored="() => [$refs.input]" @detected="visible = false">
          <div>
            <p>Text: {{ text }}</p>
            <p>Enter/ESC/Tab: will hide the popover</p>
            <p>onFocus/onClick: will show the popover</p>
          </div>
        </CInteractionOutside>
      </CPopoverContent>
    </CPopover>
  </div>
</template>
<script>
export default {
  data() {
    return {
      text: 'Edit me',
      visible: false,
    }
  },
  methods: {
    show() {
      this.visible = true
    },
    hide() {
      this.visible = false
    },
  },
}
</script>

# Close on Click Inside

This example shows you how to add a close-button inside the popover.

Show Code
<template>
  <div>
    <button ref="button" @click="toggle">Show Popover</button>

    <CPopover
      ref="popover"
      :target="() => $refs.button"
      boundary="viewport"
      with-arrow
      theme="clean"
    >
      <CPopoverContent>
        <div>
          I am a Popover Body.
          <button @click="toggle">Click here to Hide the Popover</button>
        </div>
      </CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'
export default {
  methods: {
    toggle() {
      this.$refs.popover.toggle()
    },
  },
}
</script>

# Show on Hover

The popover component is very flexible: This example shows how to show the popover on mouseenter and mouseleave. The result is a very simple tooltip.

Show Code
<template>
  <div>
    <button ref="button" @mouseenter="show" @mouseleave="hide">Tooltip shows hover</button>
    <CPopover
      ref="popover"
      :target="() => $refs.button"
      placement="bottom"
      with-arrow
      theme="clean"
    >
      <CPopoverContent>
        <div>Popover Body</div>
      </CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'
export default {
  methods: {
    show() {
      this.$refs.popover.show()
    },
    hide() {
      this.$refs.popover.hide()
    },
  },
}
</script>

# Scrollable Popover Body

If you have a popover with a (potentially) large body then you might want to make it scrollable. You do that by setting custom styles on the popover's body that constraint it's size and adjust it's overflow settings.

To make this work you have to apply custom styles to your CPopoverContent.

IMPORTANT

It is probably a good idea to also disable flipping by setting flips to false.

Show Code
<template>
  <div>
    <button ref="button" @click="toggle">Toggle Popover</button>
    <CPopover ref="popover" :target="() => $refs.button" with-arrow theme="clean" :flips="false">
      <CPopoverContent class="scroll-container">
        <p v-for="index in 35" :key="String(index)" class="text">
          I am part {{ index }} of a wonderful popover.
        </p>
      </CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'

export default {
  methods: {
    toggle() {
      this.$refs.popover.toggle()
    },
  },
}
</script>

<style scoped>
.text {
  margin-left: 0px;
  margin-right: 0px;
  margin-top: 0px;
  margin-bottom: 0px;
}
.scroll-container {
  overflow-y: scroll;
  max-width: 350px;
  max-height: 200px;
}
</style>

# Themes

# Clean

Show Code
<template>
  <div class="box">
    <button ref="button" @click="toggle">Toggle 'clean' Popover</button>
    <CPopover
      ref="popover"
      placement="bottom"
      :target="() => $refs.button"
      with-arrow
      theme="clean"
    >
      <CPopoverContent>I am a Popover. Wheeee. 😉</CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/clean.css'
export default {
  methods: {
    toggle() {
      this.$refs.popover.toggle()
    },
  },
}
</script>

<style scoped>
.box {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
}
</style>

# Dark

Show Code
<template>
  <div class="box">
    <button ref="button" @click="toggle">Toggle 'dark' Popover</button>
    <CPopover ref="popover" :target="() => $refs.button" theme="dark" with-arrow>
      <CPopoverContent>I am a Popover. Wheeee. 😉</CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/dark.css'
export default {
  methods: {
    toggle() {
      this.$refs.popover.toggle()
    },
  },
}
</script>

<style scoped>
.box {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
}
</style>

# Big Arrow

Show Code
<template>
  <div class="box">
    <button ref="button" @click="toggle">Toggle 'big-arrow' Popover</button>
    <CPopover ref="popover" :target="() => $refs.button" theme="big-arrow" with-arrow>
      <CPopoverContent>I am a Popover. Wheeee. 😉</CPopoverContent>
    </CPopover>
  </div>
</template>

<script>
import '@vue-cdk/popover/themes/big-arrow.css'
export default {
  methods: {
    toggle() {
      this.$refs.popover.toggle()
    },
  },
}
</script>

<style scoped>
.box {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
}
</style>

# API

Playground