Popover

A popup that displays information related to an element when the element receives keyboard focus, the mouse hovers over it, or it is clicked.

Component Features

  • 🛠️ Multi-direction: Supports 12 directions including top, bottom, left, right and their start/end variations.
  • 🖱️ Multiple Triggers: Supports various trigger methods such as click, hover, and focus.
  • 🎨 Theme Customization: Supports global theme customization based on BrConfigProvider, and local style overrides via TailwindCSS.

Basic Usage

The most basic popover display triggered by a click.

<script setup lang="ts">
import {
  BrPopover,
  BrPopoverTrigger,
  BrPopoverContent,
  BrPopoverArrow,
  BrPopoverClose,
  BrButton,
  BrInput
} from '@breezeui/vue'
</script>

<template>
  <BrPopover>
    <BrPopoverTrigger as-child>
      <BrButton variant="outline">Open Popover</BrButton>
    </BrPopoverTrigger>
    <BrPopoverContent 
      placement="bottom" 
      :side-offset="4" 
      class="w-80"
      @open-auto-focus="(e: Event) => e.preventDefault()"
    >
      <div class="space-y-2">
        <h4 class="font-medium leading-none">Dimensions</h4>
        <p class="text-sm text-muted-foreground">Set the dimensions for the layer.</p>
        <div class="grid gap-2 pt-4">
          <div class="grid grid-cols-3 items-center gap-4">
            <label for="width" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">Width</label>
            <BrInput id="width" model-value="100%" class="col-span-2 h-8" />
          </div>
          <div class="grid grid-cols-3 items-center gap-4">
            <label for="height" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">Height</label>
            <BrInput id="height" model-value="25px" class="col-span-2 h-8" />
          </div>
        </div>
      </div>
      <BrPopoverArrow class="fill-popover" />
      <BrPopoverClose class="absolute top-2 right-2 text-muted-foreground hover:text-foreground">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
      </BrPopoverClose>
    </BrPopoverContent>
  </BrPopover>
</template>

Position

Supports placement property to control the pop-up position, supporting 12 different directions.

<script setup lang="ts">
import {
  BrPopover,
  BrPopoverTrigger,
  BrPopoverContent,
  BrPopoverArrow,
  BrButton
} from '@breezeui/vue'

const positions = [
  'top-start',
  'top',
  'top-end',
  'right-start',
  'right',
  'right-end',
  'bottom-start',
  'bottom',
  'bottom-end',
  'left-start',
  'left',
  'left-end'
] as const
</script>

<template>
  <div class="flex flex-wrap gap-4 py-8 max-w-3xl justify-center mx-auto">
    <BrPopover v-for="pos in positions" :key="pos">
      <BrPopoverTrigger as-child>
        <BrButton variant="outline" class="w-28 text-xs">{{ pos }}</BrButton>
      </BrPopoverTrigger>
      <BrPopoverContent :placement="pos" class="w-auto p-4">
        <div class="text-sm font-medium">Placement: <span class="text-primary">{{ pos }}</span></div>
        <BrPopoverArrow class="fill-popover" />
      </BrPopoverContent>
    </BrPopover>
  </div>
</template>

Custom Trigger Methods

Supports click, hover, and focus trigger methods, which can be configured via the trigger prop.

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPopover,
  BrPopoverTrigger,
  BrPopoverContent,
  BrPopoverArrow,
  BrButton,
  BrInput
} from '@breezeui/vue'

const inputValue = ref('')
</script>

<template>
  <div class="flex gap-8 flex-col sm:flex-row items-start sm:items-center">
    <!-- Hover Trigger -->
    <BrPopover trigger="hover" :open-delay="100">
      <BrPopoverTrigger as-child>
        <span class="underline decoration-dashed underline-offset-4 cursor-help text-sm font-medium">
          Hover over me
        </span>
      </BrPopoverTrigger>
      <BrPopoverContent placement="top" class="w-64 p-3">
        <div class="text-sm">
          <strong>BreezeUI</strong> is a modern UI library based on TailwindCSS and Vue 3.
        </div>
        <BrPopoverArrow class="fill-popover" />
      </BrPopoverContent>
    </BrPopover>

    <!-- Focus Trigger -->
    <BrPopover trigger="focus">
      <BrPopoverTrigger as-child>
        <BrInput v-model="inputValue" placeholder="Focus me..." class="w-64" />
      </BrPopoverTrigger>
      <BrPopoverContent placement="bottom-start" class="w-64 p-3">
        <div class="text-sm text-muted-foreground">
          Password must be at least 8 characters long and contain a number.
        </div>
        <BrPopoverArrow class="fill-popover" />
      </BrPopoverContent>
    </BrPopover>
  </div>
</template>

Theme Customization

Combined with BrConfigProvider, you can globally override the default styles of the component. Styles can also be overridden locally via TailwindCSS.

<script setup lang="ts">
import {
  BrPopover,
  BrPopoverTrigger,
  BrPopoverContent,
  BrButton,
  BrConfigProvider
} from '@breezeui/vue'
</script>

<template>
  <BrConfigProvider
    :theme="{
      light: {
        radius: '1rem',
        popover: '220 14% 96%',
        'popover-foreground': '240 10% 3.9%',
      },
      dark: {
        radius: '1rem',
        popover: '240 10% 15%',
        'popover-foreground': '0 0% 98%',
      }
    }"
  >
    <BrPopover>
      <BrPopoverTrigger as-child>
        <BrButton>Custom Theme Popover</BrButton>
      </BrPopoverTrigger>
      <!-- Local override example -->
      <BrPopoverContent class="border-primary/20 shadow-xl p-6">
        <h4 class="font-medium mb-2">Global Theme Customization</h4>
        <p class="text-sm text-muted-foreground">
          This popover uses custom border radius and background color via BrConfigProvider.
        </p>
      </BrPopoverContent>
    </BrPopover>
  </BrConfigProvider>
</template>

Loading & Empty States

Supports displaying loading and empty states in the popover content.

<script setup lang="ts">
import {
  BrPopover,
  BrPopoverTrigger,
  BrPopoverContent,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <div class="flex gap-4">
    <BrPopover>
      <BrPopoverTrigger as-child>
        <BrButton variant="outline">Loading State</BrButton>
      </BrPopoverTrigger>
      <BrPopoverContent loading placement="bottom" />
    </BrPopover>
    
    <BrPopover>
      <BrPopoverTrigger as-child>
        <BrButton variant="outline">Empty State</BrButton>
      </BrPopoverTrigger>
      <BrPopoverContent empty placement="bottom" />
    </BrPopover>
  </div>
</template>

API Reference

BrPopover

PropTypeDefaultDescription
open (v-model)boolean-The controlled open state of the popover.
defaultOpenbooleanfalseThe default open state when initially rendered.
trigger'click' | 'hover' | 'focus' | 'manual''click'How the popover is triggered.
disabledbooleanfalseDisable the popover trigger.
openDelaynumber200Delay in ms before opening (for hover trigger).
closeDelaynumber300Delay in ms before closing (for hover trigger).

BrPopoverContent

PropTypeDefaultDescription
placement'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 'right-start' | 'right-end''bottom'Placement of the popover relative to the trigger.
sideOffsetnumber4Distance between the popover and the trigger.
maskbooleanfalseWhether to show a mask behind the popover.
loadingbooleanfalseWhether to show a loading state.
emptybooleanfalseWhether the content is empty.
closeStrategyArray<'click-outside' | 'escape' | 'scroll'>['click-outside', 'escape']Strategy for closing the popover.

BrPopoverTrigger

Used to wrap the trigger element. Use as-child to pass the event to the child element.

BrPopoverArrow

Used to display the arrow pointing to the trigger. Can be customized with class (e.g. fill-popover).

BrPopoverClose

Used to wrap the close button. Use as-child to pass the event to the child element.