WebberUI

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.

How to install Pro components →See the plans →

Loading preview…
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.

3200
<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

PropTypeDefaultDescription
titlestringHeadline text
bodystringBody paragraph
kickerstringKicker / category above the headline
metastringTrailing metadata such as a credit or byline
imageReact.ReactNodebuilt-in decorative placeholderImage visual slot (an <img> or a color block, for example)
layoutsArtLayout[]all threeWhich layouts are in the switching cycle; the order is the tab order
layoutArtLayoutControlled mode: the current layout
defaultLayoutArtLayoutfirst item of layoutsUncontrolled mode: the initial layout
onLayoutChange(layout: ArtLayout) => voidCallback when the layout changes
showSwitcherbooleantrueWhether to show the tab indicator switcher
autoPlaybooleanfalseCycle layouts automatically (paused on interaction)
intervalnumber3200Autoplay interval (milliseconds)
classNamestringAppended 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 layout measures 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 layoutId on a motion.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 a role="tabpanel" linked to the current tab with aria-labelledby
  • Tabs use a roving tabindex: the arrow keys (←→↑↓) move between layouts and Home / End jump 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

On this page