Sections
Text and media block
View in FigmaThe workhorse text-and-media section — a text tile beside an image or video frame, or a split tile carrying its own image, with surface enums and ratios.
Install
npx shadcn@latest add @alix/textAndMediaBlockPreview
Performance improvement when pace matters
Senior teams connect diagnostics, cash, and operational delivery into a practical path forward.
Usage
import { TextAndMedia, type TextAndMediaProps } from "@/components/textAndMediaBlock";
const fromCMS: TextAndMediaProps = await getBlock("performance-intro");
<TextAndMedia {...fromCMS} />
<TextAndMedia
textTileVariant="titleAndText"
textTile={{
bgColor: "primary",
sectionTitle: {
title: "Performance improvement when pace matters",
description: "Senior teams connect diagnostics, cash, and operational delivery.",
align: "start",
},
buttonGroup: {
primaryAction: {
children: "Explore capability",
rightIcon: <ArrowRight />,
render: <a href="/services/performance-improvement" />,
},
},
}}
media={{ type: "video", src: "https://samplelib.com/lib/preview/mp4/sample-5s.mp4", poster: "/article-placeholder.svg", muted: true }}
ratio="4/3"
minHeight="md"
/>Examples
01
Media leads, on a light surface
Set reverse and the media takes the leading column on desktop; a sand surface keeps the copy quiet beside it.
A senior team, close to the decision
The people who scope the work stay through delivery, so nothing is lost in the handover.
<TextAndMedia
textTileVariant="titleAndText"
textTile={{
bgColor: "sand",
sectionTitle: {
title: "A senior team, close to the decision",
description: "The people who scope the work stay through delivery.",
align: "start",
},
buttonGroup: {
primaryAction: {
children: "How we work",
rightIcon: <ArrowRight />,
render: <a href="/about/how-we-work" />,
},
},
}}
media={{ type: "image", src: "/media/grey-arc.svg", alt: "" }}
ratio="16/9"
reverse
minHeight="md"
/>02
A single large statement
The section title's largeText variant drops the title/description pair for one heading-sized statement — here on a grey-gradient surface.
Clarity, pace, and practical execution for situations where the outcome matters.
<TextAndMedia
textTileVariant="titleAndText"
textTile={{
bgColor: "greyGradient",
sectionTitle: {
variant: "largeText",
description: "Clarity, pace, and practical execution when the outcome matters.",
align: "start",
},
buttonGroup: {},
}}
media={{ type: "image", src: "/article-placeholder.svg", alt: "" }}
ratio="4/3"
minHeight="md"
/>03
Split: title, image, and body
The split variant carries its own image beside the title, then a second tile takes the description and actions — the section fills both columns from one text tile.
Two ways we engage
A senior-led diagnostic first, then a delivery team that stays through implementation.
<TextAndMedia
textTileVariant="split"
textTile={{
bgColor: "secondary",
sectionTitle: {
title: "Two ways we engage",
description: "A senior-led diagnostic first, then a team that stays through implementation.",
align: "start",
},
buttonGroup: {
primaryAction: {
children: "How we work",
rightIcon: <ArrowRight />,
render: <a href="/about/how-we-work" />,
},
},
// split carries its own image — there is no sibling media column
media: { type: "image", src: "/article-placeholder.svg", alt: "" },
}}
minHeight="md"
/>04
Video instead of a still
Flip the sibling media discriminant to video for a muted, looping clip in the frame — a poster covers it until playback starts.
Performance improvement when pace matters
Senior teams connect diagnostics, cash, and operational delivery into a practical path forward.
<TextAndMedia
textTileVariant="titleAndText"
textTile={{
bgColor: "primary",
sectionTitle: {
title: "Performance improvement when pace matters",
description: "Senior teams connect diagnostics, cash, and operational delivery.",
align: "start",
},
buttonGroup: {
primaryAction: {
children: "Explore capability",
rightIcon: <ArrowRight />,
render: <a href="/services/performance-improvement" />,
},
},
}}
media={{ type: "video", src: "https://samplelib.com/lib/preview/mp4/sample-5s.mp4", poster: "/article-placeholder.svg", autoPlay: true, muted: true, loop: true }}
ratio="16/9"
minHeight="md"
/>When to use it
Use it for
- The workhorse content section — a text tile beside an image or video, across services, insights, and about pages.
- Sections where the surface, text content, media, and ratio all vary per record.
- Leading with the media by setting reverse, or with a single statement via the section title's largeText variant.
Reach for something else
- Two text columns with no media — use TextAndTextBlock.
- A full-width media strip with no text — use MediaBannerBlock.
- next/image, a custom element, or bespoke layout — compose Grid with TextTileDefault and renderMedia directly.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| textTileVariant | "titleAndText" | "split" | — | Layout discriminant. `titleAndText` puts the tile beside a framed media column; `split` composes a title-beside-image tile plus a body tile from the same textTile. |
| textTile | TextTileDefaultProps | — | The text tile — bgColor, sectionTitle (title/description/align, largeText variant), and buttonGroup. The split variant adds its own `media` here. |
| textTile.buttonGroup | { primaryAction?; secondaryAction? } | — | Up to two actions as Button props minus `variant` — the tile maps the variant to its surface. |
| media.type | "image" | "video" | "image" | Sibling media discriminant (titleAndText only). The `split` variant uses `textTile.media` instead. |
| ratio | "1/1" | "4/3" | "3/4" | "5/4" | "4/5" | "3/2" | "2/3" | "16/10" | "16/9" | "9/16" | "3/1" | "21/9" | "16/9" | Aspect ratio for the sibling media frame. |
| reverse | boolean | false | Swaps the desktop column order; mobile keeps source order. |
| minHeight | "none" | "md" | "lg" | "xl" | "2xl" | "lg" | Minimum section height from the shared scale. |
| id | string | — | Optional anchor id for in-page navigation. |
| escape hatch | compose lower layer | — | For next/image, custom elements, or bespoke layout, compose Grid plus TextTileDefault and `renderMedia` directly. |