Skip to main content

Popover

A positioning-aware popover component for tooltips, menus, and contextual content

Popover

The Popover component provides contextual overlays that appear relative to trigger elements. Perfect for tooltips, dropdown menus, help text, and interactive content that needs precise positioning.

Position Options

Popovers can be positioned relative to their trigger element in four directions

Code

<Popover position="top">
  
  Content here
</Popover>

Position Reference

Complete list of available positioning options and their behavior

Top Centers above trigger, good for tooltips
Right Centers to the right, ideal for inline help
Bottom Centers below trigger, default position
Left Centers to the left, alternative placement

API Reference

Props

PropTypeDefaultDescription
position'top' \| 'bottom' \| 'left' \| 'right''bottom'Popover position relative to trigger
closeOnClickOutsidebooleantrueClose when clicking outside popover
closeOnEscapebooleantrueClose when pressing Escape key
classstring''Additional CSS classes
childrensnippet-Popover content
triggersnippet-Trigger element (optional)

Positioning

  • Top: Centers above the trigger element
  • Bottom: Centers below the trigger element (default)
  • Left: Centers to the left of the trigger element
  • Right: Centers to the right of the trigger element

Usage Examples

Basic Popover

<script>
  import Popover from '$lib/shared/components/overlays/Popover.svelte';
</script>

<Popover position="bottom">
  {#snippet trigger()}
    <button>Click me</button>
  {/snippet}

  <div>
    <h4>Popover Title</h4>
    <p>This is the popover content.</p>
  </div>
</Popover>

Help Tooltip

<Popover position="top">
  {#snippet trigger()}
    <Icon src="/svg/help.svg" size={16} />
  {/snippet}

  <div>
    <p>This field accepts email addresses only.</p>
  </div>
</Popover>
<Popover position="bottom">
  {#snippet trigger()}
    <button>
      Account
      <Icon src="/svg/chevron-down.svg" size={16} />
    </button>
  {/snippet}

  <div class="menu">
    <a href="/profile">Profile</a>
    <a href="/settings">Settings</a>
    <a href="/logout">Sign Out</a>
  </div>
</Popover>

Action Menu

<Popover position="bottom">
  {#snippet trigger()}
    <button>
      <Icon src="/svg/more.svg" size={16} />
    </button>
  {/snippet}

  <div class="action-menu">
    <button onclick={edit}>
      <Icon src="/svg/edit.svg" size={16} />
      Edit
    </button>
    <button onclick={duplicate}>
      <Icon src="/svg/copy.svg" size={16} />
      Duplicate
    </button>
    <button onclick={deleteItem} class="danger">
      <Icon src="/svg/trash.svg" size={16} />
      Delete
    </button>
  </div>
</Popover>

Form in Popover

<Popover position="bottom">
  {#snippet trigger()}
    <button>Quick Add</button>
  {/snippet}

  <form onsubmit|preventDefault={handleSubmit}>
    <div class="form-field">
      <label>Name</label>
      <input type="text" bind:value={name} />
    </div>
    <div class="form-actions">
      <button type="submit">Add</button>
      <button type="button">Cancel</button>
    </div>
  </form>
</Popover>

Rich Content Popover

<Popover position="bottom">
  {#snippet trigger()}
    <span class="user-mention">@john</span>
  {/snippet}

  <div class="user-card">
    <div class="user-avatar">
      <img src="/avatars/john.jpg" alt="John Doe" />
    </div>
    <div class="user-info">
      <h4>John Doe</h4>
      <p>Senior Developer</p>
      <p class="status online">Online</p>
    </div>
    <div class="user-actions">
      <button>Message</button>
      <button>View Profile</button>
    </div>
  </div>
</Popover>

Notification Popover

<Popover position="bottom">
  {#snippet trigger()}
    <button>
      <Icon src="/svg/bell.svg" size={16} />
      {#if notifications.length > 0}
        <span class="badge">{notifications.length}</span>
      {/if}
    </button>
  {/snippet}

  <div class="notifications">
    <h4>Notifications</h4>
    {#each notifications as notification}
      <div class="notification-item">
        <Icon src={notification.icon} size={16} />
        <div>
          <p>{notification.message}</p>
          <span class="time">{notification.time}</span>
        </div>
      </div>
    {/each}
    <div class="notification-footer">
      <button>Mark all as read</button>
    </div>
  </div>
</Popover>

Positioning Guide

Automatic Positioning

The Popover component uses CSS transforms to center itself relative to the trigger:

  • Top/Bottom: Horizontally centered using translateX(-50%)
  • Left/Right: Vertically centered using translateY(-50%)

Spacing and Margins

  • Default spacing between trigger and popover: var(--space-3) (12px)
  • Responsive spacing adjusts for mobile devices
  • Popover automatically maintains distance from viewport edges

Mobile Considerations

  • Reduced margins on mobile for better space utilization
  • Touch-friendly interaction areas
  • Responsive content sizing

Accessibility Features

Keyboard Navigation

  • Escape: Closes the popover
  • Tab: Moves focus to next focusable element
  • Click outside: Closes the popover (can be disabled)

Screen Reader Support

  • Uses role="dialog" for complex content
  • Proper ARIA states with aria-expanded and aria-haspopup
  • Hidden state managed with aria-hidden

Focus Management

  • Focus remains on trigger element when popover opens
  • Focus is properly managed within popover content
  • Focus returns to trigger when popover closes

Design Tokens

The Popover component uses the following design tokens:

  • Typography: --typography-caption-* for content
  • Spacing: --space-2, --space-3, --space-4
  • Colors: --surface, --border, --typography-caption-color
  • Shadows: --shadow-lg
  • Radius: --radius-md
  • Transitions: --transition-base

Best Practices

Content Guidelines

  • Keep popover content concise and focused
  • Use clear, scannable layouts for menus
  • Include visual hierarchy with icons and typography
  • Avoid overwhelming users with too many options

Positioning Strategy

  • Use bottom position for most cases (default)
  • Top position for tooltips near page bottom
  • Left/right positions for sidebar or narrow layouts
  • Consider viewport constraints in positioning

Interaction Design

  • Provide clear visual triggers (icons, arrows)
  • Use consistent trigger patterns across the application
  • Include hover states for better discoverability
  • Ensure touch targets are appropriately sized

Performance Considerations

  • Popover content is only rendered when open
  • Event listeners are properly cleaned up
  • Minimal DOM manipulation for smooth animations

Common Patterns

Contextual Help

Perfect for form field explanations and feature tooltips.

Dropdown menus for user accounts, settings, and actions.

Quick Actions

Context menus for table rows, cards, and list items.

Content Previews

Rich previews for links, users, or media content.

Form Enhancements

Quick forms, filters, and input assistance.

Technical Notes

Browser Support

  • Modern browser support with CSS Grid and Flexbox
  • Graceful degradation for older browsers
  • Mobile-optimized touch interactions

Framework Integration

  • Compatible with SvelteKit SSR
  • Works with Svelte 5 snippet syntax
  • Full TypeScript support included