Components
Component
productdevbook/ui

Stable in React

Preview Card

A link that shows a preview of its destination on hover or focus, without interrupting keyboard or screen reader navigation.

Loading React 19.3.1…
Hover a part or use it. The code follows. · Loading React…
481Tests passing in React · 0 failing
40.0 KiBSize
2.10 msOpen
1.60 msClose
0.92 MiBMemory
productdevbook and 19 upstream authors11 commits · last

Install#

One package per framework. Preview Card's parts come from it; the anatomy tab at the top shows how they nest.

bun add @▢▢▢▢/react

8 parts. The example uses six of them; the data does not say which are required.

  • PreviewCard.RootGroups all parts of the preview card.
  • PreviewCard.TriggerA link that opens the preview card.
  • PreviewCard.PortalA portal element that moves the popup to a different part of the DOM.
  • PreviewCard.PositionerPositions the popup against the trigger.
  • PreviewCard.PopupA container for the preview card contents.
  • PreviewCard.ArrowDisplays an element positioned against the preview card anchor.
  • PreviewCard.BackdropA presentational overlay displayed beneath the popup. Not in the example.
  • PreviewCard.ViewportA viewport for displaying content transitions. Not in the example.

Examples#

Common ways to put it to work. Each one runs live.

A trigger outside Root opens it through a handle.

PreviewCardDetachedTriggersSimple.tsx

Styling and accessibility#

The parts ship no styles. Style their states with these attributes; the CSS tab at the top has a sheet. The same CSS works in all five frameworks.

  • [data-popup-open]Present when the corresponding preview card is open. On Trigger.
  • [data-open]Present when the preview card is open. On Positioner, Popup, Arrow, Backdrop.
  • [data-closed]Present when the preview card is closed. On Positioner, Popup, Arrow, Backdrop.
  • [data-anchor-hidden]Present when the anchor is hidden. On Positioner.
  • [data-side]Indicates which side the popup is positioned relative to the trigger. On Positioner, Popup, Arrow.
  • [data-align]Indicates how the popup is aligned relative to specified side. On Positioner, Popup, Arrow.
  • --available-widthThe available width between the trigger and the edge of the viewport. On Positioner.
  • --available-heightThe available height between the trigger and the edge of the viewport. On Positioner.
  • --anchor-widthThe anchor's width. On Positioner.
  • --anchor-heightThe anchor's height. On Positioner.
  • --transform-originThe coordinates that this element is anchored to. Used for animations and transitions. On Positioner.
  • --positioner-widthThe width of the preview card's positioner. It is important to set width to this value when using CSS to animate size changes. On Positioner.
  • --positioner-heightThe height of the preview card's positioner. It is important to set height to this value when using CSS to animate size changes. On Positioner.
  • [data-starting-style]Present when the preview card begins animating in. On Popup, Backdrop.
  • [data-ending-style]Present when the preview card is animating out. On Popup, Backdrop.
  • [data-uncentered]Present when the preview card arrow is uncentered. On Arrow.
  • [data-current]Applied to the direct child of the viewport when no transitions are present or the new content when it's entering. On Viewport.
  • [data-previous]Applied to the direct child of the viewport that contains the exiting content when transitions are present. On Viewport.
  • [data-activation-direction]Indicates the direction from which the popup was activated. This can be used to create directional animations based on how the popup was triggered. Contains space-separated values for both horizontal and vertical axes. On Viewport.
  • [data-transitioning]Indicates that the viewport is currently transitioning between old and new content. On Viewport.
  • [data-instant]Present if animations should be instant. On Viewport.
  • --popup-widthThe width of the parent popup. This variable is placed on the 'previous' container and stores the width of the popup when the previous content was rendered. It can be used to freeze the dimensions of the popup when animating between different content. On Viewport.
  • --popup-heightThe height of the parent popup. This variable is placed on the 'previous' container and stores the height of the popup when the previous content was rendered. It can be used to freeze the dimensions of the popup when animating between different content. On Viewport.

Keyboard

  • TabFocusing the link opens the preview On Trigger.
  • EscapeCloses the preview On Popup.

Set for you

  • renders an <a> and keeps the link's own semanticsthe link is read and followed like any otherTrigger
  • not linked to the trigger and not in the tab orderscreen reader and keyboard users stay on the page and are not taken through the previewPopup
  • aria-hidden="true"the decorative arrow is not readArrow
  • role="presentation"the overlay is not readBackdrop

API reference#

28 props across 8 parts, in React syntax, and className, style, render once for every part. Open a row to try it.

PreviewCard · all parts
Shared propsEvery part that renders an element takes these.
classNameCSS class applied to the element, or a function that returns a class based on the component's state.string | ((state: State) => string | undefined)
styleStyle applied to the element, or a function that returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>

Use it in React#

What differs from the React API. Switch the framework at the top of the page.

@▢▢▢▢/react is the React 19 package. Its parts, props, data attributes and error messages are upstream Base UI's, and upstream's own tests run against it.

  • Parts

    Each component is its own entry point and exports one namespace named after it.

    import { Switch } from '@base-ui-next/react/switch'
    
    export function Example() {
      return (
        <Switch.Root>
          <Switch.Thumb />
        </Switch.Root>
      )
    }

    A part renders the element its API reference names, such as a <span> for Switch.Root.

  • Props and events

    Props and callbacks have upstream's names and signatures: onCheckedChange(checked, details), onOpenChange(open, details), onValueChange(value, details). details carries reason, event, cancel() and allowPropagation(). Native handlers are React's (onClick, onKeyDown), and event.preventBaseUIHandler() stops a part's own handler.

  • Styling

    className takes a string or a function (state) => string; style takes an object or a function (state) => object. The state's data-* attributes are on the element for CSS.

  • render

    render takes an element (render={<a href="/docs" />}) or a function (props, state) => element that spreads props on what it returns.

  • Refs

    ref reaches the part's element. Imperative handles are ref props, as upstream: inputRef, and actionsRef ({ validate } on Field and Form, { unmount, close } on Dialog).

  • Binding

    A part is controlled when its value prop (checked, open, value) is set, and uncontrolled with the default form (defaultChecked, defaultOpen, defaultValue). React has no two-way binding: pair the value with its change callback.

  • From @base-ui/react
    Change the import from @base-ui/react/<component> to @▢▢▢▢/react/<component>.
  • From @base-ui/react
    Nothing else changes: props, parts, data attributes and errors are the same.