ATOM
Components (registry)Actions

Image

A responsive frame for media from thumb to hero. Product shots and section visuals.

Preview

Sizes: xssmlherofull (default: xs)

Editorial

<!-- F12c editorial — non-derivable only. Review: Karen. -->

## Ejemplos

Product shot with ratio and cover fit:

```tsx import { Image } from '@/components/atoms/Image';

<Image src="/product/hero.jpg" alt="Atom UIKit components on a light surface" size="hero" ratio="16x9" fit="cover" radius="lg" /> ```

## Accesibilidad

- `alt` is mandatory for meaningful images; use empty `alt=""` only when the image is pure decoration next to adjacent text that already names it. - Default `loading="lazy"` — override to `eager` for LCP heroes above the fold.

## Cuándo no usar

- Avatars / people faces → `Avatar` (sizes, status, initials). - Icons and UI glyphs → icon components / SVG, not `Image` with a huge bitmap.

Uso

import { Image } from '@/components/atoms/Image';

<Image
  src="/photos/hero.jpg"
  alt="Team workshop"
  size="l"
  ratio="16x9"
  fit="cover"
  radius="md"
/>

Props

PropTipoDefaultRango / opcionesWhatHow
sizeselect`xs`, `s`, `m`, `l`, `hero`, `full`Intrinsic display size of the image frame.m for cards; l/hero for marketing; full for edge-to-edge bands. Default: m.
ratioselect`1x1`, `4x3`, `16x9`, `21x9`Aspect ratio lock for the frame before load.16x9 for video thumbs; 1x1 for avatars/product tiles; 21x9 only for cinematic heroes.
fitselect`cover`, `contain`object-fit strategy inside the frame.cover for crops/heroes; contain when the whole asset must stay visible (logos, diagrams).
radiusselect`none`, `sm`, `md`, `lg`, `xl`, `full`Corner rounding of the image frame.md for cards; full only for circular crops; none for full-bleed media.

Gotchas

  • a11y

    Always pass meaningful alt (or alt="" only when purely decorative and adjacent text already names it).

  • react

    Forwards native img attributes; do not nest interactive buttons inside without a separate control pattern.

Anatomía CSS

<div class="image">

</div>
ClasePropósito
imageroot
image--containmodifier
image--covermodifier
image--fullmodifier
image--heromodifier
image--lmodifier
image--loadedmodifier
image--loadingmodifier
image--mmodifier
image--ratio-16x9modifier
image--ratio-1x1modifier
image--ratio-21x9modifier
image--ratio-4x3modifier
image--rounded-fullmodifier
image--rounded-lgmodifier
image--rounded-mdmodifier
image--rounded-nonemodifier
image--rounded-smmodifier
image--rounded-xlmodifier
image--smodifier
image--xsmodifier

Tokens resueltos

Valores finales tras seguir la cadena de tokens. Derivados del source: si un token cambia, esta tabla cambia sola.

VariantePropValorToken
allbg#f5f5f5muted

Animaciones

PropiedadDuraciónEasing
opacityvar(--duration-300)var(--easing-out)

CSS mínimo funcional

Autocontenido: sin imports ni tokens. Para previews y prototipos — en producción se consume el CSS del DS (@atom-uikit/css/components.css</code>, <code>@atom-uikit/tokens/tokens.css).

/* ============================================================
   Image — responsive image with sizing variants and aspect ratios
   ============================================================ */

.image {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
  object-fit: cover;
  border-radius: 8px;
  background-color: #f5f5f5;
  transition: opacity 300ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---- Sizing variants ---- */
.image--xs {
  width: 3rem; /* 48px */
  height: 3rem;
  border-radius: 4px;
}

.image--s {
  width: 6rem; /* 96px */
  height: 6rem;
  border-radius: 8px;
}

.image--m {
  width: 12.5rem; /* 200px */
  height: auto;
}

.image--l {
  width: 25rem; /* 400px */
  height: auto;
}

.image--hero {
  width: 100%;
  max-height: 30rem; /* 480px */
  object-fit: cover;
  border-radius: 16px;
}

.image--full {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
}

/* ---- Aspect ratios ---- */
.image--ratio-1x1 { aspect-ratio: 1 / 1; }
.image--ratio-4x3 { aspect-ratio: 4 / 3; }
.image--ratio-16x9 { aspect-ratio: 16 / 9; }
.image--ratio-21x9 { aspect-ratio: 21 / 9; }

/* ---- Object fit variants ---- */
.image--contain { object-fit: contain; }
.image--cover { object-fit: cover; }

/* ---- Border radius variants ---- */
.image--rounded-none { border-radius: 0; }
.image--rounded-sm { border-radius: 4px; }
.image--rounded-md { border-radius: 8px; }
.image--rounded-lg { border-radius: 12px; }
.image--rounded-xl { border-radius: 16px; }
.image--rounded-full { border-radius: 9999px; }

/* ---- Loading state (skeleton placeholder) ---- */
.image--loading {
  opacity: 0;
}

.image--loaded {
  opacity: 1;
}

/* ---- Reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  .image {
    transition-duration: 0ms;
  }
}

Codigo fuente

components-react
components/atoms/Image.tsx
import { forwardRef, useState, type ImgHTMLAttributes } from 'react';

export type ImageSize = 'xs' | 's' | 'm' | 'l' | 'hero' | 'full';
export type ImageRatio = '1x1' | '4x3' | '16x9' | '21x9';
export type ImageFit = 'cover' | 'contain';
export type ImageRadius = 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';

export type ImageProps = {
  size?: ImageSize;
  ratio?: ImageRatio;
  fit?: ImageFit;
  radius?: ImageRadius;
  className?: string;
} & Omit<ImgHTMLAttributes<HTMLImageElement>, 'className'>;

function cn(...classes: (string | false | undefined | null)[]) {
  return classes.filter(Boolean).join(' ');
}

export const Image = forwardRef<HTMLImageElement, ImageProps>(
  ({ size, ratio, fit, radius, className, loading = 'lazy', onLoad, ...props }, ref) => {
    const [loaded, setLoaded] = useState(false);

    const classes = cn(
      'image',
      size && `image--${size}`,
      ratio && `image--ratio-${ratio}`,
      fit && `image--${fit}`,
      radius && `image--rounded-${radius}`,
      !loaded && 'image--loading',
      loaded && 'image--loaded',
      className,
    );

    return (
      <img
        ref={ref}
        className={classes}
        loading={loading}
        onLoad={(e) => {
          setLoaded(true);
          onLoad?.(e);
        }}
        {...props}
      />
    );
  },
);

Image.displayName = 'Image';

Webflow

Webflowimage

Pega en el Designer como application/json, luego convierte a Component (Atom / Image) y publica. Formato interno no documentado de Webflow — regenerable, no dependencia de runtime.

Setup del sitio (una vez)

Custom Code → Head:

<link rel="stylesheet" href="https://atom-web-ds.vercel.app/v1/tokens.css">
<link rel="stylesheet" href="https://atom-web-ds.vercel.app/v1/components.css">

Unsupported (no silencioso)

  • @media on (prefers-reduced-motion: reduce)not a Designer breakpoint — moved to head Custom Code block

Tras pegar: Create component → nombre Atom / Image → Publish.

On this page

Detalles

Publicado14 de mayo de 2026
Categoriaactions
Lectura...
Visitas...
Ayuda?Slack

Componente

Image

Source

components-react / cssDisponible via MCP: atom_uikit_source("image")