Popover

Rich content in a panel that opens from a button.

import { … } from '@inlaylab/ivorie/popover'
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IvButton } from '@inlaylab/ivorie/button';
import { IV_INPUT_IMPORTS } from '@inlaylab/ivorie/input';
import { IV_POPOVER_IMPORTS } from '@inlaylab/ivorie/popover';

@Component({
  selector: 'demo-popover',
  imports: [IV_POPOVER_IMPORTS, IV_INPUT_IMPORTS, IvButton],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-popover>
      <button ivButton ivPopoverTrigger variant="outline">Open popover</button>
      <iv-popover-content class="w-80">
        <iv-popover-header>
          <iv-popover-title>Dimensions</iv-popover-title>
          <iv-popover-description>Set the dimensions for the layer.</iv-popover-description>
        </iv-popover-header>
        <div class="grid grid-cols-3 items-center gap-3">
          <label ivLabel for="pop-width">Width</label>
          <input ivInput id="pop-width" value="100%" class="col-span-2 h-8" />
          <label ivLabel for="pop-height">Height</label>
          <input ivInput id="pop-height" value="25px" class="col-span-2 h-8" />
        </div>
      </iv-popover-content>
    </iv-popover>
  `,
})
export default class PopoverDemo {}

Installation

CLInpm
npx ivorie add popover

Usage

import { IV_POPOVER_IMPORTS } from '@inlaylab/ivorie/popover';
<iv-popover>
  <button ivButton ivPopoverTrigger>Open</button>
  <iv-popover-content>
    <iv-popover-title>Title</iv-popover-title>
    Content
  </iv-popover-content>
</iv-popover>

Examples

Align

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IvButton } from '@inlaylab/ivorie/button';
import { IV_POPOVER_IMPORTS } from '@inlaylab/ivorie/popover';

@Component({
  selector: 'demo-popover-align',
  imports: [IV_POPOVER_IMPORTS, IvButton],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div class="flex flex-wrap justify-center gap-3">
      @for (a of aligns; track a) {
        <iv-popover>
          <button ivButton ivPopoverTrigger variant="outline" size="sm">{{ a }}</button>
          <iv-popover-content [align]="a" class="w-40">
            <iv-popover-title>Aligned {{ a }}</iv-popover-title>
          </iv-popover-content>
        </iv-popover>
      }
    </div>
  `,
})
export default class PopoverAlignDemo {
  protected readonly aligns = ['start', 'center', 'end'] as const;
}

API

Every part also accepts class.

iv-popover

Name Type Default Description
open boolean (two-way) false Open state.

iv-popover-content

Name Type Default Description
side 'top' | 'right' | 'bottom' | 'left' 'bottom' Side of the trigger. Flips when there is no room.
align 'start' | 'center' | 'end' 'center' Alignment along that side.
sideOffset number 4 Gap to the trigger, in px.
alignOffset number 0 Shift along the side, in px.

Other parts

  • [ivPopoverTrigger]: toggles the popover.
  • [ivPopoverAnchor]: positions the content against this element instead of the trigger.
  • iv-popover-header, iv-popover-title, iv-popover-description.

Accessibility

  • The content is role="dialog", labelled by iv-popover-title.
  • Opening moves focus into the content. Tab stays inside. Escape or a click outside closes it and returns focus to the trigger.