Skip to content

UI: Popover Component #220

@mihar-22

Description

@mihar-22

Blocked by:

Implement a compound Popover component for Video.js 10, providing the foundation for tooltips, menus, and other floating UI elements.

The Popover handles:

  • Positioning: Anchor-based positioning with CSS Anchor Positioning (fallback to Floating UI)
  • Interactions: Hover, focus, and click triggers with configurable delays
  • Transitions/Animations: CSS-driven via data attributes, supports both transition and @keyframes
  • Safe polygons: Prevents accidental close when moving pointer from trigger to popup
  • Collision avoidance: Keeps popup within specified boundaries

Usage

React

<Popover.Root openOnHover delay={200}>
  <Popover.Trigger>
    <button>Hover me</button>
  </Popover.Trigger>
  <Popover.Portal>
    <Popover.Positioner placement="top" sideOffset={8}>
      <Popover.Popup>
        <Popover.Arrow />
        Popover content
      </Popover.Popup>
    </Popover.Positioner>
  </Popover.Portal>
</Popover.Root>

HTML

<button popovertarget="my-popover">Hover me</button>

<media-popover
  id="my-popover"
  open-on-hover
  delay="200"
  placement="top"
  side-offset="8"
>
  Popover content
</media-popover>

API

Tasks

Core (@videojs/core)

  • Implement PopoverCore extending ComponentCore base class
  • Element ref setters using ElementNode type (React Native compatible subset of DOM)
  • Open/close/toggle methods with callback invocation
  • Interaction handlers for pointer, focus, and keyboard events
  • Position computation using Floating UI (offset, flip, shift, hide middleware)
  • Transition state machine (closed → initial → open → closing → closed)
  • Safe polygon calculation for hover intent (port from Floating UI)
  • Timer management for hover delays

Callouts:

  • Element refs stored on class instance, not in state
  • No DOM APIs in core—use ElementNode interface with getBoundingClientRect() and contains()
  • notifyTransitionEnd() method for frameworks to call when CSS animations/transitions complete

DOM (@videojs/core/dom)

  • Define data attributes and css vars interfaces for each part.
  • getPopoverTriggerProps() returning ARIA attrs and anchor styles
  • getPopoverPopupProps() returning data attributes and positioning styles
  • Feature detection for CSS anchor positioning support
  • Two style outputs: CSS anchor positioning (when supported) and Floating UI fallback

Callouts:

  • Data attributes for CSS: data-open, data-closed, data-starting-style, data-ending-style, data-side
  • Fallback required—CSS anchor positioning only ~75% browser support

React (@videojs/react)

  • Context for sharing core instance and state across compound parts
  • Popover.Root — Provider, instantiates core, syncs props/callbacks
  • Popover.Trigger — Clones child with trigger props and event handlers
  • Popover.Portal — Optional portal rendering
  • Popover.Positioner — Positioning wrapper, sets collision boundary
  • Popover.Popup — Main popup element with animation detection
  • Animation/transition end detection hook that calls core.notifyTransitionEnd()

Callouts:

  • Support both controlled (open prop) and uncontrolled (defaultOpen) modes
  • Must detect completion of both CSS transitions AND @Keyframes animations

HTML (@videojs/html)

  • <media-popover> custom element with observed attributes
  • Lifecycle management (create/destroy core, subscribe/unsubscribe)
  • Trigger discovery via [popovertarget="${id}"] selector
  • Collision boundary discovery via closest('[data-media-container]')
  • Animation end listeners for transition completion

Testing

  • Core unit tests
  • Add conformance suite
  • Add React conformance test
  • Add HTML conformance test

Documentation

  • Create /docs/html/components/popover docs page. Include demos, anatomy, examples, and API reference.
  • Create /docs/react/components/popover docs page. Include demos, anatomy, examples, and API reference.

Acceptance Criteria

  • Opens/closes via click, hover, and focus
  • Configurable delays work correctly
  • Collision detection keeps popover within bounds
  • CSS anchor positioning used when supported, Floating UI fallback otherwise
  • Both CSS transitions and @keyframes animations work
  • onOpenChangeComplete fires after animations finish
  • React and HTML produce identical DOM structure
  • Safe polygon prevents accidental close
  • Core has no DOM dependencies (uses ElementNode interface)

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions