Image
A responsive image, styled. Uses the native <img> element directly;
for source negotiation (AVIF / WebP / JPEG fallback) authors wrap it
in <picture>. CSS-only.
When to use
- Display a single image with the design system's visual conventions (rounded corners, shadow, aspect ratios).
- Inside Cards, Heroes, Avatars — anywhere a styled
<img>is the right primitive.
For animated icons paired with state changes, use
@malevich/morph-icons. For decorative SVG, embed the SVG directly.
Loading defaults
Per the design decision recorded with this component: eager
loading is the default. Authors opt in to lazy loading explicitly via
data-lazy="true" and the matching loading="lazy" attribute on
the <img>.
<!-- Eager (default) — typical for above-the-fold content -->
<img class="image" src="hero.jpg" alt="…" width="1200" height="600" />
<!-- Lazy — typical for below-the-fold media in long pages -->
<img class="image" src="footer.jpg" alt="…"
width="800" height="400"
loading="lazy" data-lazy="true" />
The data-lazy attribute is a marker for tooling and AGENTS.md
generation; browsers honor only loading="lazy". Authors pair both.
Variants
| Variant | Class | Use for |
|---|---|---|
| Default | .image |
Plain responsive image |
| Rounded | .image.-rounded |
Card-radius corners |
| Pill | .image.-pill |
Pill-shape (full radius) |
| Circle | .image.-circle |
Circular crop (1:1 aspect) |
| Cover | .image.-cover |
object-fit: cover, fills container |
| Contain | .image.-contain |
object-fit: contain |
| Bordered | .image.-bordered |
Hairline border |
| Shadow | .image.-shadow |
Raised shadow |
Modifiers compose: .image.-rounded.-shadow.-bordered.
Anatomy
<!-- Plain -->
<img class="image" src="…" alt="…" width="600" height="400" />
<!-- With source negotiation -->
<picture>
<source srcset="hero.avif" type="image/avif" />
<source srcset="hero.webp" type="image/webp" />
<img class="image -rounded -shadow" src="hero.jpg" alt="…"
width="1200" height="600" />
</picture>
<!-- With srcset for density / size -->
<img class="image -cover"
src="card.jpg"
srcset="card.jpg 1x, card@2x.jpg 2x"
alt="…"
width="400" height="400" />
<!-- Avatar-style circle -->
<img class="image -circle -bordered"
src="user.jpg" alt="Alex K." width="64" height="64" />
Tokens used
From semantic tier
--color-border-default— bordered variant--radius-card— rounded variant--radius-pill— pill variant--shadow-raised— shadow variant--border-width-hairline— border thickness
Accessibility
<img> requires a meaningful alt attribute:
- For informative images: describe the content.
- For decorative images: use
alt=""(empty). Do NOT omit the attribute. - For complex images (charts, diagrams): use
altfor short summary and a longer description in surrounding text or viaaria-describedby.
The component does not impose any alt-text behavior; it is the
author's responsibility. The linter will eventually flag <img class="image"> without alt (v1.1).
To prevent cumulative layout shift (CLS), always set width and
height attributes on <img> so the browser reserves the correct
aspect ratio. The CSS sets block-size: auto so the rendered size
scales while preserving the intrinsic ratio.
Edge cases
- Inside a flex/grid container: the default
display: blockandmax-inline-size: 100%lets the image scale within its container without overflow. - Aspect ratio preservation: use the
width/heightHTML attributes for intrinsic ratio. Avoid setting these in CSS only — the browser needs the attributes to reserve space before the image loads. - AVIF / WebP fallback: use
<picture>with<source>elements. The component class goes on the inner<img>(which is also the final fallback for browsers without<picture>support). - Broken images: the native broken-image icon shows by default.
Use
onerrorto swap a fallback if needed; the component does not ship a fallback strategy.
Do
- Always set
widthandheightattributes. - Always set
alt(usealt=""for decorative). - Wrap in
<picture>when you have multiple source formats. - Pair
data-lazy="true"withloading="lazy".
Don't
- Don't omit
alt. - Don't lazy-load above-the-fold images — it delays Largest Contentful Paint.
- Don't use this component for background images. Use CSS
background-imageon a div.