Aspect Ratio
stimeo--aspect-ratio
Hands a chosen aspect ratio to CSS. Keeping the box proportional stays with your styles.
A small layout helper that hands a chosen aspect ratio to CSS and nothing more. It has no role and no state, so it changes nothing for screen readers. It takes both the `16/9` form and a plain number. A value it cannot read falls back to one to one. Change the value and it is reflected straight away. Making the box hold that ratio stays with your styles, so how an image is cropped inside it remains your decision.
Keyboard
This component has no keyboard interactions of its own.
<%# Markup for the aspect-ratio demo.
The library only supplies the ratio Value as the --stimeo--aspect-ratio custom
property; demo.css does the actual ratio rendering
(aspect-ratio: var(--stimeo--aspect-ratio)). %>
<div class="aspect-ratio-demo">
<figure class="aspect-ratio-demo__item">
<div class="ratio-box" data-controller="stimeo--aspect-ratio"
data-stimeo--aspect-ratio-ratio-value="16/9">
<div class="ratio-box__content">16 / 9</div>
</div>
<figcaption><%= t("components.aspect_ratio.demo.wide") %></figcaption>
</figure>
<figure class="aspect-ratio-demo__item">
<div class="ratio-box" data-controller="stimeo--aspect-ratio"
data-stimeo--aspect-ratio-ratio-value="1/1">
<div class="ratio-box__content">1 / 1</div>
</div>
<figcaption><%= t("components.aspect_ratio.demo.square") %></figcaption>
</figure>
<figure class="aspect-ratio-demo__item">
<div class="ratio-box" data-controller="stimeo--aspect-ratio"
data-stimeo--aspect-ratio-ratio-value="3/4">
<div class="ratio-box__content">3 / 4</div>
</div>
<figcaption><%= t("components.aspect_ratio.demo.portrait") %></figcaption>
</figure>
</div>
/* Presentation CSS for aspect-ratio. The library only supplies
--stimeo--aspect-ratio, so this CSS reads it with var() and draws the ratio. */
.aspect-ratio-demo {
display: flex;
gap: 1.5rem;
flex-wrap: wrap;
align-items: flex-start;
}
.aspect-ratio-demo__item {
margin: 0;
font-size: 0.85rem;
color: var(--color-text-muted);
display: flex;
flex-direction: column;
gap: 0.5rem;
}
/* Feed the ratio the library supplies straight into CSS aspect-ratio. */
.ratio-box {
width: 200px;
aspect-ratio: var(--stimeo--aspect-ratio);
border: 2px dashed var(--border-interactive);
border-radius: 8px;
background: repeating-linear-gradient(
45deg,
var(--surface-subtle),
var(--surface-subtle) 10px,
var(--surface-subtle) 10px,
var(--surface-subtle) 20px
);
}
.ratio-box__content {
width: 100%;
height: 100%;
display: grid;
place-items: center;
font-weight: 600;
color: var(--color-text);
}
This demo needs no consumer-side JS (the controller handles the behavior).
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--aspect-ratio"
Values
| Name | Description | Attribute |
|---|---|---|
ratio
|
The CSS <ratio> to apply (e.g. 16/9 or a bare number); defaults to 1/1 and falls back to it when unparseable. |
data-stimeo--aspect-ratio-ratio-value |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
--stimeo--aspect-ratio |
Host element | The ratio (e.g. 16 / 9). Consumer CSS reads it. |