Layout
Theme
The Motion root: applies fonts, tokens, base styles and the light/dark appearance to everything inside, including portalled menus and dialogs.
Usage
Use it to:
- wrap the whole app once (on
<body>withasChild) - force a section into the other appearance (a nested
<Theme appearance="dark">); its overlays follow it - portal your own floating UI with
<ThemePortal>so it keeps the Theme’s appearance
Don’t use it to:
- styling outside Motion components (Motion styles only apply inside a Theme and its overlays)
- raw
createPortalor a Radix*.Portalto<body>for Motion surfaces (they lose the Theme’s appearance)
Installation
Install the package (React 19):
Import the styles once, in your app entry or root layout:
Use it anywhere inside your app's <Theme> (see Installation):
Examples
Appearance
light, dark, or system (follows the OS; renders light on the server, then updates after mount).
Mixed themes
Light and dark Themes can share a page. Menus, popovers, selects, tooltips and dialogs open in the appearance of the Theme they belong to, not of the page.
Next.js root layout
Use asChild to make <body> the root, so portalled overlays sit inside it.
Reading the theme
Your own floating UI
ThemePortal is the portal every Motion overlay uses. Wrap custom floating elements in it; pass primitive={X.Portal} when rendering a Radix primitive yourself.
API Reference
Theme
A <div> (or your element with asChild) with the motion-root class; supports all <div> props. Adds:
| Prop | Type | Default |
|---|---|---|
appearance | "light""dark""system" | "light" |
asChild | boolean | false |
ThemePortal
Renders its children into the nearest Theme’s portal layer: a container on <body> carrying that Theme’s light/dark class and custom properties. Outside a Theme it renders into <body>.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | |
primitive | PortalPrimitive | |
forceMount | true | |
container | Element | DocumentFragment | null |
useTheme()
The nearest Theme’s appearance. Throws outside a <Theme>.
| Prop | Type | Default |
|---|---|---|
appearance | "light""dark""system" | |
resolvedAppearance | "light""dark" |
Accessibility
- Sets
color-scheme, so native controls and scrollbars match the theme. - Every text token pair meets WCAG AA (4.5:1) in both themes;
systemrespects the user’s OS preference. - Theme adds no landmarks or roles; use
asChildon<body>or<main>when you want its semantics. - Overlays render in the Theme’s portal layer at the end of
<body>: focus is still trapped in dialogs and returned to the trigger on close, and modal dialogs hide the rest of the page from assistive technology as usual. - Each overlay keeps the contrast of the Theme it opened from, so a light Theme’s menu never turns dark because a dark section is on the page.