1

Motion And Reduced Motion

The global motion provider, shared tokens and component motion families used by Siteplane UI.

Siteplane UI ships motion with the components. Product screens normally compose primitives without adding transitions, durations or transforms of their own.

Provider setup

Mount one SiteplaneMotionProvider at the application root, outside components that render portals:

import { SiteplaneMotionProvider } from "@/motion";

export function AppProviders({ children }: { children: React.ReactNode }) {
  return <SiteplaneMotionProvider>{children}</SiteplaneMotionProvider>;
}

The provider writes the active --motion-* variables and reduced-motion state to document.documentElement, so dialogs, menus, tooltips and other portals share the same contract.

Motion families

FamilyComponentsBehavior
Floating panelsMenu, Select, Combobox, Autocomplete, Popover, Preview Card, TooltipShared fade, scale and directional anchor offset
Expand and collapseAccordion, CollapsibleTokenized intrinsic-height transition
Modal overlaysDialog, Alert Dialog, Command, SheetSeparate backdrop and panel transitions
Direct manipulationDrawer, SliderNative swipe or drag behavior with tokenized finishing states
State feedbackButton, Toggle, Switch, Tabs, Progress, ToastSmall component-owned transitions
Loading feedbackSpinner, SkeletonContinuous animation in normal mode; a static semantic status or placeholder in reduced motion

Reduced motion

The default mode follows the operating-system preference through prefers-reduced-motion. The exported reducedMotionPreset provides an explicit application override: it shortens shared durations, removes transform distances and writes data-motion-reduce="true" for component contracts that need a forced static state.

Spinner and Skeleton stop their continuous animation in both modes while their status or placeholder shape remains visible. Finite token-based transitions either stop through their component media rule or use the shorter preset duration documented on that component page.

Do not remove keyboard, focus, dismissal or direct-manipulation behavior when motion is reduced. Reduced motion changes presentation, not capability.

Button scale

Button hover and press feedback use shared scale tokens. Set scale={false} when a Button is the trigger inside a composition where scaling would move the complete anchored control:

<PopoverTrigger render={<Button scale={false} variant="outline" />}>
  Filters
</PopoverTrigger>

This disables both hover and press scale while preserving color, shadow, focus and disabled feedback. Omitting the prop keeps the native Button behavior.

Customization

The exported siteplaneDefaultMotion config and motionConfigToCssVars connect typed configuration to CSS variables. Change the central configuration when an application deliberately needs a different global motion scale; do not scatter duration-*, ease-*, scale-* or arbitrary transform classes through feature code.

import {
  SiteplaneMotionProvider,
  siteplaneDefaultMotion,
} from "@/motion";

const motion = {
  ...siteplaneDefaultMotion,
  global: {
    ...siteplaneDefaultMotion.global,
    durationScale: 0.8,
  },
};

<SiteplaneMotionProvider config={motion}>
  <App />
</SiteplaneMotionProvider>;

Rules

  • Mount one provider for the application.
  • Let primitives own their native transitions.
  • Use component props such as Button scale={false} before overriding classes.
  • Keep durations, easing, distance and scale in the central motion config.
  • Test keyboard behavior and focus with both normal and reduced motion.

On This Page