Skip to content
weftGitHub

Frame

A box that holds its shape, for images, video and previews.

SourcePackage @weft-js/warpPlayground

Preview

tsx
import { Frame, Grid, Text } from '@weft-js/warp'export function Ratios() {  return (    <Grid min="xs" cols={6} gap="related">      {RATIOS.map(ratio => (        <Frame key={ratio} ratio={ratio}>          <Text role="caption" subtle>{ratio}</Text>        </Frame>      ))}    </Grid>  )}const min = 60_000const RATIOS = ['21:9', '16:9', '3:2', '4:3', 'square', '3:4'] as const

Installation

npm install @weft-js/warp

Usage

tsx
import { Frame } from '@weft-js/warp'<Grid min="xs" cols={6} gap="related">  {RATIOS.map(ratio => (    <Frame key={ratio} ratio={ratio}>      <Text role="caption" subtle>{ratio}</Text>    </Frame>  ))}</Grid>

Media crops to fit

An image, video, canvas or SVG directly inside fills the frame and crops.

tsx
import { Frame, Grid } from '@weft-js/warp'export function Media() {  return (    <Grid min="xs" cols={3} gap="related">      <Frame>{art('1', '3')}</Frame>      <Frame ratio="square">{art('2', '5')}</Frame>      <Frame ratio="3:4">{art('4', '7')}</Frame>    </Grid>  )}const min = 60_000const art = (a: string, b: string) => (  <svg viewBox="0 0 320 180" preserveAspectRatio="xMidYMid slice" aria-hidden="true">    <rect width="320" height="180" fill={`var(--warp-color-data-${a})`} />    <circle cx="96" cy="150" r="130" fill={`var(--warp-color-data-${b})`} />    <rect x="176" y="36" width="104" height="108" rx="8" fill="var(--warp-color-surface)" opacity="0.85" />  </svg>)

Deploy previews

Use ratio to give each preview the same shape, here 16:9.

tsx
import { Card, Frame, Grid, Stack, Text } from '@weft-js/warp'export function Previews() {  return (    <Grid min="sm" cols={3} gap="related">      {DEPLOYS.slice(0, 3).map((d, n) => (        <Card key={d.id}>          <Stack gap="related">            <Frame ratio="16:9">{art(String(n + 1), String(n + 4))}</Frame>            <Stack gap="hair">              <Text role="heading">{d.project}</Text>              <Text role="caption" subtle>{d.message}</Text>            </Stack>          </Stack>        </Card>      ))}    </Grid>  )}const DEPLOYS = [  { id: 'd-4821', project: 'storefront', branch: 'main', commit: '9f3ac21', message: 'Cache product images at the edge', author: 'Priya Raman', status: 'Live', minutes: 2, at: '2026-10-31T16:42' },  { id: 'd-4820', project: 'search-api', branch: 'ranking-v2', commit: '1be07d4', message: 'Rank exact matches first', author: 'Lena Fischer', status: 'Building', minutes: 6, at: '2026-10-31T16:10' },  { id: 'd-4819', project: 'mobile-bff', branch: 'main', commit: 'c44e190', message: 'Retry timed out upstream calls', author: 'Sam Okafor', status: 'Failed', minutes: 4, at: '2026-10-31T15:27' },  { id: 'd-4818', project: 'checkout', branch: 'main', commit: '70d2fa8', message: 'Add Apple Pay to the last step', author: 'Tomás Oliveira', status: 'Live', minutes: 3, at: '2026-10-31T14:03' },  { id: 'd-4817', project: 'edge-cache', branch: 'main', commit: 'e81b6c2', message: 'Lower the stale window to 30s', author: 'Jun Tanaka', status: 'Live', minutes: 1, at: '2026-10-31T11:55' },  { id: 'd-4816', project: 'billing', branch: 'main', commit: '2ad9e03', message: 'Prorate seats on plan change', author: 'Mara Lindqvist', status: 'Live', minutes: 3, at: '2026-10-29T17:20' },]const min = 60_000const change = (a: number, b: number) => `${a >= b ? '+' : ''}${((a - b) / b * 100).toFixed(1)}%`const art = (a: string, b: string) => (  <svg viewBox="0 0 320 180" preserveAspectRatio="xMidYMid slice" aria-hidden="true">    <rect width="320" height="180" fill={`var(--warp-color-data-${a})`} />    <circle cx="96" cy="150" r="130" fill={`var(--warp-color-data-${b})`} />    <rect x="176" y="36" width="104" height="108" rx="8" fill="var(--warp-color-surface)" opacity="0.85" />  </svg>)

When to use

Use it for

  • Images and video that must not shift the page as they load
  • Thumbnails of mixed sizes that should line up

Reach for something else

  • Card, when it needs a surface and padding

Playground

import { Frame } from '@weft-js/warp'<Frame>  <img src="/preview.png" alt="" /></Frame>

Accessibility

  • Frame draws nothing itself, so give an image its alt as usual.

API Reference

PropTypeDefaultDescription
childrenunknown—What it contains.
as"div" | "section" | "article" | "main" | "header" | "footer" | "nav" | "…—The element it renders as.
gap"section" | "none" | "hair" | "tight" | "related" | "group" | "page"—The space between children, from warp's space scale.
ratio"square" | "4:3" | "3:2" | "16:9" | "21:9" | "3:4" | "9:16"'16:9'Width to height. 16:9 by default.

RelatedCardGrid