Holds an image or video at a fixed ratio, so layouts never jump while media loads.
FreeWeb and MobileMotion
Preview
npx shadcn add @fetaui/aspect-ratioPlaygroundGolden hour over the dunes · 16:9
RatiosGolden hour over the dunes · 1:1 Golden hour over the dunes · 4:3 Golden hour over the dunes · 3:2 Golden hour over the dunes · 16:9 Golden hour over the dunes · 21:9 Golden hour over the dunes · 9:16
Video
2:14
Loading
Empty, drop a file or press Upload
Error
CaptionGolden hour over the dunes · 16:9
Ratio
Content
Icons animation
Caption
Motion
Installation
Terminal· bash
npx shadcn add @fetaui/aspect-ratio
Caption
Visible text under the frame. Alt text stays for screen readers.
Ratio
Caption
Accessibility
- Always give images alt text. The caption is visible, alt is for screen readers.
- Play is a real button named Play video with the duration.
- Errors are announced as they appear.
Motion
- A band sweeps the frame every 1400 ms while loading, and pauses off screen.
- Loaded media fades, sharpens from 8 px and settles from 1.02 in 320 ms. The frame never resizes.
- Dragging over Empty inks the ring and fill in 150 ms.
- With reduced motion, Loading holds a still 5% fill and media fades in 120 ms.
Responsive behavior
- Fills its column. Width times the ratio gives the height.
- Play grows from 44 to 52 and Upload from 28 to 36 on Mobile, and the caption from 12 to 14 px.
Performance
- The box reserves its space before media loads, so the layout never jumps.
- The Loading shimmer is CSS and pauses off screen.
Note for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Import AspectRatio and AspectRatioScene. Props: ratio, src, alt, content, caption, duration, onPlay, onFile, uploading, onRetry.
- With src the state follows the load: Loading, then the image or Error. alt is required with src.
- AspectRatioScene is a drawn stand-in. Replace it with real media.
- The demo's upload is a timer. Wire onFile and uploading.
Related
SkeletonComponentA placeholder in the shape of content on its way, so nothing jumps when it arrives.CarouselComponentA rail of tall cards. The centred card grows to 106% and shows its price.CardComponentThe container most of fetaUI is built on: an inset card on a soft tray, with actions on the tray.AttachmentComponentA file on its way up or already there, with a drop zone and an upload queue.Reveal ImageProBlockA photo that resolves out of a dither field the first time it scrolls into view, then assembles into colour.