Vertical Writing Spread
A Chinese/Japanese vertical writing editorial layout built with CSS writing-mode — vertical columns flow right to left with horizontal pull quotes and images interleaved between them, text reveals character by character from top to bottom on entry, and horizontal scrolling advances the column order.
This is a WebberUI Pro component
The install command below needs a licence to run; without one it returns 401.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add "https://webberui.com/r/vertical-writing-spread.en.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.
<VerticalWritingSpread/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add "https://webberui.com/r/vertical-writing-spread.en.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/vertical-writing-spread.
Usage
Use VerticalWritingSpread as the container and place vertical VerticalColumn and horizontal HorizontalInsert elements inside it in reading order. The layout flows right to left, so the first column sits at the far right; the container needs a fixed height (the vertical columns fill it):
import {
VerticalWritingSpread,
VerticalColumn,
HorizontalInsert,
} from "@/components/ui/vertical-writing-spread";
<VerticalWritingSpread className="h-[320px]" showProgress fadeEdges>
<VerticalColumn variant="heading">Vertical Order</VerticalColumn>
<VerticalColumn>The text flows in vertical columnsFlowing, from the rightLeftReads……</VerticalColumn>
<HorizontalInsert>
<blockquote>“White space is not blank, but breathing.”</blockquote>
</HorizontalInsert>
<VerticalColumn>HorizontalQuotes and images appear throughout, giving your eyes a place to rest……</VerticalColumn>
<VerticalColumn variant="heading">The layout is the narrative.</VerticalColumn>
</VerticalWritingSpread>Vertical columns reveal character by character from top to bottom as they come into view. wheelToHorizontal is on by default, so a vertical wheel turns into horizontal advancement through the columns, releasing page scrolling automatically once either end is reached.
Props
VerticalWritingSpread
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | — | Place VerticalColumn and HorizontalInsert in reading order; they are laid out right to left |
gap | number | 32 | Horizontal gap between columns (px) |
columnHeight | number | string | "100%" | Height of the vertical columns; fills the container by default, so the container needs its own fixed height |
wheelToHorizontal | boolean | true | Turn a vertical wheel into horizontal advancement through the columns, releasing page scrolling at the boundaries |
showProgress | boolean | false | Show a horizontal reading progress bar at the bottom |
fadeEdges | boolean | false | Fade the left and right edges with a mask, hinting that there is more to scroll |
stagger | number | 0.05 | Interval between characters as a vertical heading enters (seconds) |
duration | number | 0.7 | Duration of a single column's or character's entrance (seconds) |
once | boolean | true | Plays the reveal animation only the first time it comes into view |
ariaLabel | string | "Vertical writing spread" | accessible label applied to the scrollable region |
className | string | — | Appended to the outer scrollable container's className (set the height here) |
trackClassName | string | — | Appended to the inner horizontal track's className (left and right padding, for instance) |
VerticalColumn
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "heading" | "body" | "body" | heading is a large vertical heading (a plain string enters character by character), body is vertical body text |
children | React.ReactNode | — | The column content; passing a string to a heading lets it reveal character by character |
writingMode | "vertical-rl" | "vertical-lr" | "vertical-rl" | Direction of the vertical writing |
className | string | — | Appended to the column container's className |
HorizontalInsert
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | — | A horizontal block interleaved between vertical columns: a pull quote, an image, or a caption |
align | "start" | "center" | "end" | "center" | Vertical alignment within the vertical flow |
className | string | — | Appended to the block container's className |
How it works
- Vertical writing is built with CSS
writing-mode: vertical-rl, so the body text descends vertically and wraps automatically into multiple vertical lines;HorizontalInsertbreaks the vertical flow withhorizontal-tbto carry horizontal pull quotes and images - The layout runs right to left: the track uses
flex-row-reverse, the first column sits at the far right, and it scrolls to the far right automatically on mount, matching the Chinese and Japanese reading direction - Entrance detection is driven by IntersectionObserver (with the scroll container as the root); headings reveal character by character from top to bottom with a stagger, and body columns are revealed top-down via
clip-path wheelToHorizontalmaps the vertical wheel onto horizontal advancement, so scrolling down moves the column order forward (to the left); once either end is reached, page scrolling is released rather than locked
Accessibility
- The scrollable region is a focusable
role="region"with anaria-label;ArrowDown/Spaceadvance andArrowUpgoes back, switching between smooth and instant scrolling according to reduced motion - Character-by-character headings keep an
sr-onlycopy of the complete text, and the split graphemes are hidden from assistive technology (aria-hidden), so what is announced is complete words and phrases - When the user has "reduce motion" enabled at the system level, the vertical writing layout and horizontal scrolling are preserved and only the reveal and stagger animations are disabled (the content appears in full immediately)
Pull Quote Lift
When a sentence inside a paragraph scrolls into the viewport, a shared-element animation lifts it out and scales it up into a full-width pull quote, dropping it back inline when it leaves the viewport.
Chaptered Report Shell
An annual-report / white-paper page shell — a sticky chapter rail generated automatically from the content, giant chapter numbers cross-fading between chapters, full-bleed color-block transitions between sections, and a dual reading-progress indicator.