A picture arrives after the layout has already been decided, so the space it will take is
the one thing on the page nobody knows in advance, and the jump it makes when it lands is
the layout shift everybody notices and nobody attributes. So `Image` states the frame
first: `ratio` claims the space, `fit` decides how the picture fills it, a skeleton holds
the frame until the file is there, and `fallbackSrc` covers the source that never arrives.

What separates it from its siblings is the scope. `Card.image` composes this component
inside a card's own placement rules and `Avatar` composes it in a fixed circular frame;
`Image` is the picture on its own, with the frame stated by the page, and the two seams
the others inherit, the error fallback and the framework's own image component, are stated
here.

```tsx demo="data-display/image-preview"
```

## Usage

```tsx
import { Image } from "@asheeui/web";

<Image src="/campaign.png" alt="Autumn campaign artwork" ratio="video" />
```

A source and its alternative text are the whole requirement. Everything else has a value
already: an `auto` ratio, a `cover` fit, the application's `defaultRadius`, lazy loading and a
skeleton that shows until the picture is there.

## Ratio and fit

`ratio` takes four keys: `auto`, which is the source's own proportions; `square`, 1:1;
`video`, 16:9; and `portrait`, 3:4. The frame is drawn from the ratio rather than from the
file, so a column of pictures settles once instead of reflowing as each source arrives.

`fit` is the element's own `object-fit`, with the five behaviours the browser defines:
`cover` crops the source to the frame, `contain` letterboxes it inside the frame, `fill`
stretches it, `none` keeps it at its natural size and `scale-down` is the smaller of `none`
and `contain`.

```tsx demo="data-display/image-ratios"
```

Both options are registered, so a page of product photography states `components.image.fit`
and `components.image.ratio` once rather than on every picture. `ratio="auto"` is the
absence of a frame: the height then comes from the file, which is what one picture inside a
story wants and what a row of thumbnails does not.

## Loading and the error fallback

Until the picture is there, the frame holds a skeleton: a pulsing wash, hidden from
assistive technology, removed as soon as the source reports itself loaded. The picture
fades in over 300ms, so the arrival is a fade rather than a flash. A source the browser has
already cached reports itself complete when the element mounts, so a picture the reader has
seen before renders without the placeholder at all.

`fallbackSrc` is the second source. When the first fails, `Image` swaps it in and tries
again; `onError` is called only when there is nothing left to try, which is either no
fallback or a fallback that failed too. So a handler is about the picture the reader did
not get rather than the one that was replaced. `onLoad` follows the same rule from the
other side: it reports the picture that finally renders, so with a fallback in play it
fires for the substitute.

```tsx demo="data-display/image-fallback"
```

`showSkeleton` (registered `true`) turns the placeholder off, which is what a picture
behind text wants. `loading` (registered `lazy`) is the browser's own deferral, `eager` is
the right value for the picture above the fold. It is the web's option alone: a native
picture is a view, fetched when the view mounts, so the native renderer's configuration
omits it rather than accepting a value it would ignore.

## A framework's image

A framework's image component knows what a bare `<img>` does not, the intrinsic size, the
loader, the allowed host, so `Image` renders `component` in place of the element and
forwards `componentProps` to it. The substitute receives the element's own props, `src`,
`alt`, `className`, `loading` and the load and error handlers, with `componentProps` merged
last, so a key stated in both places is the component's.

```tsx
import NextImage from "next/image";

<Image
  src="/campaign.png"
  alt="The autumn campaign"
  ratio="video"
  component={NextImage}
  componentProps={{ sizes: "(min-width: 768px) 50vw, 100vw" }}
/>
```

When `component` is stated and `componentProps` gives neither `width`/`height` nor `fill`,
`Image` adds `fill: true` and `sizes: "100%"`, because the frame is what decides the shape:
the picture fills it rather than carrying its own dimensions. `loading` and `priority` are
forwarded exactly as given, a substituted component's own defaults are its business, so
`Image` supplies `loading: "eager"` only when neither the instance nor `componentProps` states
one, and never rewrites `priority`. This is the same seam every navigation component uses for
its links, see [Links and substitution](/concepts/substitution).

## Props

```props Image
```

`fit`, `ratio`, `loading` and `showSkeleton` are registered with the values above, so
`components.image` retunes every picture in the application at once.

`radius` is deliberately **not** registered, so a picture follows the application's
`defaultRadius` exactly as a control does: the framework's own configuration rounds both to
`xs`, and `md` is only the fallback when no tier states one. That is what lets a product state
its rounding once; an application that wants pictures rounder than its controls states
`components.image.radius`.

`src`, `alt`, `fallbackSrc`, `component`, `componentProps` and the native attributes are
instance-only, because a source, its description and the component that renders it are
statements about one picture rather than about the design.

## Accessibility

- The element is a real `<img>` inside a `<span>` that carries only the frame, so the
  picture is announced by its `alt` and by nothing else. `Image` never invents a
  description: state `alt`, and use `alt=""` for a picture that is decoration.
- The skeleton is `aria-hidden`, so a reader is never told about a placeholder that is about
  to be replaced.
- The frame is the ratio, so the space is claimed before the request starts: a reader's
  place in the page does not move when the picture loads.
- A source with no working fallback keeps its alternative text on screen, so a failed
  picture is still described rather than left as an empty box.
- A substituted component is given `alt` like the element is. If it drops the prop, the
  picture is unnamed, and it needs the dimensions or the `fill` its own contract requires,
  which `componentProps` is for.

## Related

```related card, avatar, link
```
