Files
2026-05-27 23:47:53 +01:00

6.2 KiB

AspectRatio

(no submodules)

- aspect-ratio.variants — `aspectRatioVariants` is th…
  • aspect-ratio.variants — aspectRatioVariants is the cva (class-variance-authority) configuration powering the <AspectRatio> outer wrapper. I…

  • aspect-ratio.variants — aspectRatioVariants is th…

  • aspect-ratio.variants — aspectRatioVariants is the cva (class-variance-authority) configuration powering the <AspectRatio> outer wrapper. I…

  • aspect-ratio.variants — aspectRatioVariants is th…

  • aspect-ratio.variants — aspectRatioVariants is the cva (class-variance-authority) configuration powering the <AspectRatio> outer wrapper. I…

  • aspect-ratio.variants — aspectRatioVariants is th…

  • aspect-ratio.variants — aspectRatioVariants is the cva (class-variance-authority) configuration powering the <AspectRatio> outer wrapper. I…

  • aspect-ratio.variants — aspectRatioVariants is the cva (class-variance-authority) configuration powering the <AspectRatio> outer wrapper. I…

Purpose

<AspectRatio> is the chassis fixed-aspect-ratio container built on @radix-ui/react-aspect-ratio. Radix sizes the inner box via inline padding-bottom so the rendered element preserves the requested numeric ratio at every viewport width — the wrapping <div> then serves as a positioning context for any embedded <img>, <video>, <iframe>, or other layout-sensitive child. The chassis layers a small cva recipe (relative w-full overflow-hidden) so embedded media slot in cleanly without consumers having to remember the boilerplate every time.

The component is purely structural — it takes the requested ratio prop, sizes the box, and renders children. No translations, no theming axes, no event handlers. The Radix primitive does not assign a numeric z-index and neither does the chassis, so stacking remains implicit.

Features

  • Wraps @radix-ui/react-aspect-ratio with a chassis-friendly cva slot.
  • ratio prop accepts any positive number (16 / 9, 4 / 3, 1, 21 / 9, …); Radix interprets it as width / height.
  • relative w-full overflow-hidden baked in so embedded <img className="h-full w-full object-cover"> or <iframe className="absolute inset-0 size-full"> children sit correctly.
  • Forwards refs to the rendered <div>.
  • Theme-driven cva override via useThemedVariants("AspectRatio").
  • No translations and no a11y semantics required (the box is layout-only).

Usage: Basic Example

import { AspectRatio } from "@suaveplan/react-ui";

export function CoverImage({ src, alt }: { src: string; alt: string }) {
    return (
        <AspectRatio ratio={16 / 9}>
            <img
                src={src}
                alt={alt}
                className="h-full w-full object-cover"
            />
        </AspectRatio>
    );
}

Usage: Advanced Example

import { AspectRatio, cn } from "@suaveplan/react-ui";

interface MediaTileProps {
    readonly kind: "image" | "video" | "embed";
    readonly src: string;
    readonly alt?: string;
    readonly title?: string;
}

export function MediaTile({ kind, src, alt, title }: MediaTileProps) {
    return (
        <AspectRatio
            ratio={kind === "video" ? 16 / 9 : kind === "embed" ? 4 / 3 : 1}
            className={cn(
                "rounded-lg border bg-muted",
                kind === "embed" && "shadow-md"
            )}
        >
            {kind === "image" ? (
                <img
                    src={src}
                    alt={alt ?? ""}
                    className="h-full w-full object-cover"
                />
            ) : kind === "video" ? (
                <video
                    src={src}
                    controls
                    className="h-full w-full object-cover"
                    aria-label={title}
                />
            ) : (
                <iframe
                    src={src}
                    title={title ?? "Embed"}
                    className="absolute inset-0 size-full border-0"
                />
            )}
        </AspectRatio>
    );
}

API Reference

<AspectRatio>

Renders the Radix Root which constrains the box to the supplied numeric ratio.

Prop Type Default Description
ratio number 1 Desired width / height ratio. Radix uses it to compute the padding-bottom percentage.
className string none Additional classes merged via cn() after the chassis cva recipe.
children ReactNode none The content to be sized to the ratio. Position children with className="h-full w-full object-cover" or className="absolute inset-0 size-full" for full-bleed behaviour.

Forwards refs to the rendered <div> element.

aspectRatioVariants(): string

Returns the chassis cva class string. Takes no arguments. Useful when assembling a custom slot that wants the same recipe without rendering an <AspectRatio>.

Implementation Notes

  • The cva carries relative so embedded children using absolute inset-0 (e.g. iframes) anchor correctly. Without it, the absolutely-positioned child escapes to the nearest positioned ancestor.
  • overflow-hidden is included so rounded corners on className="rounded-lg" clip the embedded media — without it, <img> overflow would leak out the corners.
  • w-full ensures the wrapper fills the parent's width; the height is then computed by Radix from the ratio. Consumers can override with className="w-1/2" or similar when a fixed-width tile is desired.
  • The chassis NEVER assigns a numeric z-index; stacking is the consumer's responsibility (typically managed by a surrounding overlay primitive such as <Dialog>).
  • Radix's primitive accepts ratio as a number; passing 0 or a negative value results in invalid CSS. The chassis does not validate at runtime — supply a positive ratio.
  • Because the component is purely structural, there are no translation keys to override and no a11y semantics injected. Any media inside should carry its own alt / title / aria-label per WAI-ARIA practice.