Aspect Ratio
AccessibilityBrick 0.1.2

Aspect Ratio

Aspect Ratio reserves stable width-to-height geometry for authored media, embeds, placeholders, and layout content. It controls the box and optional frame only; children retain their own semantics, sizing, and behavior.

Live example

Built from the published package

Interactive
16 : 9
Choose with confidence

Know when Aspect Ratio is the right part

Use it when

Use Aspect Ratio when content needs a predictable shape before loading, or when a generic media/embed boundary needs consistent clipping, radius, or neutral frame paint.

Choose another path when

Use Image for image loading, fallback, fit, and focal position. Use Surface for a general panel and Skeleton for a loading placeholder. Aspect Ratio is not a video player, map, gallery, optimizer, cropper, or responsive-value system.

Installation and imports

tsx
import { AspectRatio } from "@flowstack-ui/brick";
// or
import { AspectRatio } from "@flowstack-ui/brick/aspect-ratio";
import "@flowstack-ui/brick/styles.css";

The complete stylesheet above is the recommended default. For a measured route-aware build, replace it with the shared foundation and this component's stylesheet:

tsx
import "@flowstack-ui/brick/styles/core.css"; // once at the application root
import "@flowstack-ui/brick/styles/aspect-ratio.css";

Add the modular stylesheet for every other Brick component the route renders. Do not combine modular styles with styles.css or tokens.css.

The subpath also exports AspectRatioRoot, AspectRatioRootProps, AspectRatioVariant, AspectRatioRadius, and AspectRatioOverflow.

Quick start

tsx
<AspectRatio.Root ratio={16 / 9} radius="lg" variant="outline">
  <iframe title="Product tour" src="/tour" />
</AspectRatio.Root>

Size the child explicitly when it should fill the box:

tsx
<AspectRatio.Root ratio={4 / 3} overflow="hidden" radius="md">
  <img
    alt="Team reviewing a release"
    src="/release.jpg"
    style={{ blockSize: "100%", inlineSize: "100%", objectFit: "cover" }}
  />
</AspectRatio.Root>

Visual recipes and states

plain is transparent, subtle supplies a neutral canvas, and outline supplies a neutral canvas plus a one-pixel boundary. Radius changes only corner geometry. Overflow changes only clipping. full intentionally produces a capsule or ellipse for non-square ratios.

Aspect Ratio has no hover, active, selected, loading, disabled, validation, or focus state of its own.

Examples

Square placeholder

tsx
<AspectRatio.Root ratio={1} radius="full" variant="subtle">
  <span aria-hidden="true" />
</AspectRatio.Root>

Semantic embed

tsx
<AspectRatio.Root ratio={16 / 9} radius="lg" variant="outline">
  <iframe
    allow="fullscreen"
    src="/map"
    style={{ blockSize: "100%", inlineSize: "100%" }}
    title="Office location"
  />
</AspectRatio.Root>
Public contract

API

Start with the public parts and root options below. Components with multiple parts separate each area into its own named subsection.

Root

PropValuesDefault
ratiopositive number16 / 9
variantplain, subtle, outlineplain
radiusnone, sm, md, lg, fullnone
overflowvisible, hiddenhidden

Atom normalizes zero, negative, NaN, and infinite ratios to 16 / 9. ratio is width divided by height. Native CSS only uses the preferred ratio when at least one physical dimension remains automatic.

Shared responsibility

Accessibility

Aspect Ratio adds no role, name, state, keyboard behavior, focusability, or announcement. Children own semantics: images need suitable alt text, iframes need descriptive titles, and videos need applicable controls and captions. With clipped overflow, ensure descendant focus indicators remain visible or use overflow="visible"/an inset focus style.

Responsive behavior

Root is block-level, inline-size contained, and fills its available inline size. It does not provide responsive prop objects or named ratio tokens. Compose responsive CSS outside Root when a ratio must change by container or viewport. Geometry is direction-neutral and identical in RTL. Dark and forced colors affect optional frame paint; the component has no motion.

Stable visual contract

Styling and tokens

Customization

Override variables on a class or appearance scope:

css
.product-preview {
  --brick-aspect-ratio-background: var(--brick-color-accent-subtle);
  --brick-aspect-ratio-border-color: var(--brick-color-accent-border);
  --brick-aspect-ratio-radius: 1rem;
}

Consumer className and style are preserved. A style.aspectRatio value is overridden by the authoritative ratio prop.

Tokens and CSS hooks

Public variables:

  • --brick-aspect-ratio-background
  • --brick-aspect-ratio-border-color
  • --brick-aspect-ratio-border-width
  • --brick-aspect-ratio-radius
  • --brick-aspect-ratio-overflow

Public hooks are .brick-aspect-ratio, data-slot / [data-slot] with data-slot="aspect-ratio", [data-variant], [data-radius], and [data-overflow]. Atom's inline ratio is deliberately not a Brick CSS variable.

Advanced reference

Open these details only when you need to inspect DOM ownership, native forwarding, or lower-level composition.

Maintainer resources

Tests, playground evidence, source notes, and release history remain available without crowding the plug-and-play guide.