Art Direction Morph
One set of headline, image, and body copy morphing seamlessly between several magazine-grade layouts with FLIP layout animation, plus a keyboard-driven tab indicator switcher.
This is a WebberUI Pro component
Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.
npx shadcn@latest add "https://webberui.com/r/art-direction-morph.json?t=<install token>"Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<ArtDirectionMorph />
Installation
npx shadcn@latest add "https://webberui.com/r/art-direction-morph.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/art-direction-morph.
Usage
Pass in one set of content and the component switches it between three layouts — Swiss grid, brutalist asymmetric, and classical centered. On a switch every element flies into its new place with a FLIP animation, and the type scale and column widths transition along with it:
import { ArtDirectionMorph } from "@/components/ui/art-direction-morph";
<ArtDirectionMorph
kicker="Editorial · Issue 12"
title="One set of content, three layouts"
body="The headline, image, and body copy morph seamlessly between layouts with FLIP layout animation."
meta="Photography — W. Weber"
/>;Controlled mode
Passing layout and onLayoutChange enters controlled mode, with the current layout owned by outside state; omit layout (optionally with defaultLayout) for uncontrolled mode, where the component manages it internally:
const [layout, setLayout] = React.useState<ArtLayout>("swiss");
<ArtDirectionMorph
layout={layout}
onLayoutChange={setLayout}
title="Headline"
body="Body copy"
/>;Autoplay and custom layouts
Use autoPlay to cycle layouts automatically (paused on hover or focus), and layouts to restrict and order the available layouts:
<ArtDirectionMorph
autoPlay
interval={3000}
layouts={["classical", "swiss"]}
title="Headline"
body="Body copy"
/>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Headline text |
body | string | — | Body paragraph |
kicker | string | — | Kicker / category above the headline |
meta | string | — | Trailing metadata such as a credit or byline |
image | React.ReactNode | built-in decorative placeholder | Image visual slot (an <img> or a color block, for example) |
layouts | ArtLayout[] | all three | Which layouts are in the switching cycle; the order is the tab order |
layout | ArtLayout | — | Controlled mode: the current layout |
defaultLayout | ArtLayout | first item of layouts | Uncontrolled mode: the initial layout |
onLayoutChange | (layout: ArtLayout) => void | — | Callback when the layout changes |
showSwitcher | boolean | true | Whether to show the tab indicator switcher |
autoPlay | boolean | false | Cycle layouts automatically (paused on interaction) |
interval | number | 3200 | Autoplay interval (milliseconds) |
className | string | — | Appended to the outermost container's className |
ArtLayout is "swiss" | "brutalist" | "classical" (Swiss grid / brutalist asymmetric / classical centered).
How it works
- All three layouts share the same DOM elements and only swap CSS grid positions and typography classes; Motion's
layoutmeasures the before and after bounds with FLIP so elements fly into their new places, with type scale and column widths transitioning on a spring at the same time - The layout switcher is a sliding indicator block using
layoutIdon amotion.span, which glides smoothly to the selected tab - The image slot accepts any
ReactNode; when omitted it shows the built-in gradient crop placeholder
Accessibility
- The switcher uses
role="tablist"/role="tab"semantics, and the composition area is arole="tabpanel"linked to the current tab witharia-labelledby - Tabs use a roving tabindex: the arrow keys (←→↑↓) move between layouts and
Home/Endjump to the first and last, with focus following - The current layout is announced to screen readers through a hidden
aria-live="polite"region - When the user has "reduce motion" enabled at the system level, FLIP and autoplay are disabled and a layout change cuts straight to position with no transition
String Pinboard
A red-string pinboard layout — cards are clues pinned to corkboard, connected by red strings that sag naturally, with slack and droop changing live as you drag.
Paste-Up Assembly
Blocks scattered like paste-up cuttings that fly back into their grid slots with FLIP as you scroll in, and scatter apart again when you scroll back.