easeul

Base UITransitions

Popover

The origin chain falls back to the Base UI variable when the Radix one is absent, so one rule serves both libraries.

Every value the manifest allows on this host, single presets and the pairs that compose. The first is what this component ships with. Both stages are the same component, so anything that changes between them is the attribute.

withoutno attribute
with easefuldata-motion="scale-fade"
host writes

data-ending-style, data-side, --transform-origin

easeful matches

[data-motion][data-side] { transform-origin: <anchor origin> }

what runs

transition, origin from the trigger

you write

<Popover.Popup data-motion="scale-fade" />

Where the attribute goes

The parts this demo composes, and the value each one carries. Everything inside an animated part is that part's content, so the tree stops there.

  1. Popover.Root
  2. Popover.Trigger
  3. Popover.Portal
  4. Popover.Positioner
  5. Popover.Popupdata-motion="scale-fade"

Source

"use client"

import { Popover } from "@base-ui/react/popover"
import type { DemoProps } from "@/components/demos/props"

export function BaseUiPopover({ motion }: DemoProps) {
  return (
    <Popover.Root>
      <Popover.Trigger className="btn">Open popover</Popover.Trigger>
      <Popover.Portal>
        <Popover.Positioner sideOffset={10} collisionPadding={16}>
          <Popover.Popup className="panel" data-motion={motion}>
            <p className="panel__title">Anchored</p>
            <p className="panel__body">
              Base UI publishes its own transform origin, which easeful falls back to when the
              Radix one is absent.
            </p>
          </Popover.Popup>
        </Popover.Positioner>
      </Popover.Portal>
    </Popover.Root>
  )
}
The whole file, read from disk at build time. Both copies above render from it, and the motion prop is the only difference between them.