Aspect-ratio-preserving figure slot for hero media with optional frame, tone border, and caption.
- Four ratio presets (1/1, 4/5, 16/10, 16/9) reserve layout to prevent CLS
- Optional framed border driven by surface + tone tokens
- Renders as semantic figure/figcaption when caption is provided
- Surface-aware (pixel / linear) frame and corners
- Status
- stable
- Category
- hero
- Since
- v1.7.0
import { PixelHeroMedia } from '@pxlkit/ui-kit';
| Prop | Type | Default | Description |
|---|
ratio | '1/1' | '4/5' | '16/10' | '16/9' | '16/10' | Aspect ratio of the figure. |
anchor | 'center' | 'baseline-headline' | 'center' | Centred across its row, or on the row's end beside a headline. |
framed | boolean | false | Draw the surface border and radius in the tone's border colour. |
tone | 'neutral' | 'green' | 'cyan' | 'gold' | 'red' | 'purple' | 'pink' | 'neutral' | Tone of the frame. |
caption | string | — | Caption under the media, in a <figcaption>. |
captionClassName | string | — | Optional className applied to the inner caption (figcaption). |
surface | 'pixel' | 'linear' | — | Surface override; defaults to the nearest provider. |
children* (required) | React.ReactNode | — | The media. |
Also takes the native attributes and event handlers of its element (HTMLAttributes<HTMLElement>).
ref points to its element (HTMLElement).
WCAG target: 2.1 AA
figure/figcaption when caption presentaspect-ratio reserves layout to avoid CLS
Caption is rendered inside a <figcaption> when provided; otherwise the media stands alone inside <figure>.
import { PixelHeroMedia } from '@pxlkit/ui-kit';
const Placeholder = ({ label }: { label: string }) => (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-cyan-500/20 to-purple-500/20 text-xs font-mono text-retro-muted">
{label}
</div>
);
export function Default() {
return (
<PixelHeroMedia ratio="16/10">
<Placeholder label="16:10 media" />
</PixelHeroMedia>
);
}
Examples
Default
import { PixelHeroMedia } from '@pxlkit/ui-kit';
const Placeholder = ({ label }: { label: string }) => (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-cyan-500/20 to-purple-500/20 text-xs font-mono text-retro-muted">
{label}
</div>
);
export function Default() {
return (
<PixelHeroMedia ratio="16/10">
<Placeholder label="16:10 media" />
</PixelHeroMedia>
);
}
Framed with caption
import { PixelHeroMedia } from '@pxlkit/ui-kit';
const Placeholder = ({ label }: { label: string }) => (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-cyan-500/20 to-purple-500/20 text-xs font-mono text-retro-muted">
{label}
</div>
);
export function Framed() {
return (
<PixelHeroMedia ratio="16/9" framed tone="cyan" caption="Framed hero with caption">
<Placeholder label="16:9 framed" />
</PixelHeroMedia>
);
}
Square (1:1)
import { PixelHeroMedia } from '@pxlkit/ui-kit';
const Placeholder = ({ label }: { label: string }) => (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-cyan-500/20 to-purple-500/20 text-xs font-mono text-retro-muted">
{label}
</div>
);
export function Square() {
return (
<PixelHeroMedia ratio="1/1" framed tone="purple">
<Placeholder label="1:1 square" />
</PixelHeroMedia>
);
}