Image
Content & statusBrick 0.1.12

Image

Image presents ordinary raster or vector media with authored alternative text, deterministic loading/fallback anatomy, fit and focal-position recipes, stable aspect ratio, and finished framing. Atom owns source lifecycle; Brick owns paint.

Live example

Built from the published package

Interactive
Brick artwork
Choose with confidence

Know when Image is the right part

Use it when

Use Image for project thumbnails, article media, product screenshots, and other ordinary responsive media that needs a stable frame, crop/contain behavior, or an authored unavailable state.

Use Image for a larger editorial or profile portrait when its authored aspect ratio, crop, focal position, or available measure communicates identity. Use Avatar instead for a compact fixed-square identity token.

Choose another path when

Use Avatar for compact fixed-square people or entity identity, Icon for inline SVG symbols, and Surface.Media for decorative layered background media. Image is not an optimizer, gallery, lightbox, figure/caption, upload editor, or framework image loader.

Installation and imports

tsx
import { Image } from "@flowstack-ui/brick";
// or
import { Image } from "@flowstack-ui/brick/image";
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/image.css";

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

Public exports are Image, ImageRoot, ImageContent, ImageFallback, ImageRootProps, ImageContentProps, ImageFallbackProps, ImageFit, ImagePosition, ImageRadius, and ImageFrame. Direct parts are equivalent to the compound namespace and support imports from React Server Components without a client wrapper around Image.

Quick start

tsx
<Image.Root src="/workspace.jpg" ratio={16 / 9}>
  <Image.Content alt="Designers reviewing the workspace" width={1200} height={675} />
  <Image.Fallback>Image unavailable</Image.Fallback>
</Image.Root>

Visual recipes and states

Fit changes only object-fit; position changes only object-position. Logical start/end reverse under RTL without mirroring pixels. Radius clips the complete frame. frame="none" reserves no border geometry, so embedded media reaches the Root edge. frame="subtle" adds a semantic canvas and one-pixel border. Ratio reserves the box; without it, loaded native dimensions remain intrinsic.

Atom exposes data-state="idle | loading | loaded | error". Content appears only when loaded. Authored Fallback fills the same reserved box for its selected states.

Examples

Decorative media inside a named link

tsx
<Link aria-label="Open workspace" href="/workspace">
  <Image.Root asChild src="/workspace.jpg" ratio={16 / 9}>
    <span><Image.Content alt="" /></span>
  </Image.Root>
</Link>

Separate loading and error content

tsx
<Image.Root src={source} frame="subtle">
  <Image.Content alt="Quarterly report chart" />
  <Image.Fallback when="loading">Loading chart</Image.Fallback>
  <Image.Fallback when={["idle", "error"]}>Chart unavailable</Image.Fallback>
</Image.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
srcimage URL stringabsent / idle
fitcover, contain, fill, none, scale-downcover
positioncenter, top, bottom, start, endcenter
radiusnone, sm, md, lg, fullnone
framenone, subtlenone
ratiopositive finite numberintrinsic
fillbooleanfalse
onLoadingStatusChange(status) => voidnone

Content and Fallback

Image.Content requires alt. It forwards native image attributes including width, height, srcSet, sizes, loading, decoding, fetchPriority, crossOrigin, referrerPolicy, events, data/ARIA attributes, class, style, and its image ref. src belongs to Root.

Image.Fallback accepts Atom when="idle" | "loading" | "error" or an array of those values. Its default covers all three non-loaded states. All parts retain Atom render and asChild composition.

fill makes Root, Content, and Fallback consume a block size established by the parent. It is useful for media slots and other deliberately sized regions:

tsx
<Surface.Media>
  <Image.Root fill fit="cover" src="/workspace.jpg">
    <Image.Content alt="" height={675} width={1200} />
  </Image.Root>
</Surface.Media>

fill does not position Image absolutely or infer geometry. The parent must establish the available block size; fit and position still control the pixels inside it. Prefer ratio when the image should establish its own box.

Shared responsibility

Accessibility

Every Content requires an authored alt decision. Use concise contextual alt for informative media and alt="" for decoration. Inside an already named action, the image is usually decorative. Never repeat nearby text, derive a name from a filename, or write “image of.” Complex images need adjacent extended content.

For a profile portrait, use the person's name when the portrait communicates identity beyond the surrounding copy. Use alt="" only when that specific portrait is intentionally decorative; the mere presence of a nearby name does not establish one universal answer.

Fallback adds no live region, focus, role, or generated announcement. Add application status messaging only when a source change matters to the task. Image has no keyboard interaction. Forced colors preserves a visible subtle frame and readable fallback.

Responsive behavior

Root and Content stay within their available inline size. Native width/height reserve intrinsic ratio; srcSet and sizes let the browser choose a source. Image defines no breakpoints. Its owner chooses surrounding Grid, Stack, Container, and responsive dimensions.

For delivery-sensitive images, keep the source directly discoverable and do not lazy-load a measured or strongly expected LCP image. Use eager loading and reserve fetchPriority="high" for the small number of genuinely critical images. Ordinary below-fold images may use native lazy loading. If a product requires an exact proximity or intent boundary, the application should decide when to attach the source; native lazy loading remains a browser scheduling hint rather than an exact scroll threshold.

Image does not generate formats, resize assets, choose a CDN, emit document preloads, or decide a product's critical path. Those remain application, framework-adapter, build, or hosting responsibilities. Qualify delivery with cold and warm visits, narrow and wide source selection, constrained loading, blocked media, transferred bytes, and layout-shift evidence.

Stable visual contract

Styling and tokens

Customization

Prefer recipes, then override component variables for a deliberate exception:

tsx
<Image.Root
  frame="subtle"
  style={{ "--brick-image-frame-background": "var(--brick-color-accent-soft)" }}
>
  <Image.Fallback>Preview unavailable</Image.Fallback>
</Image.Root>

Classes and inline styles remain escape hatches. Applications own source selection, optimization, priority policy, and fallback content.

Tokens and CSS hooks

Stable classes are .brick-image, .brick-image__content, and .brick-image__fallback. Stable slots are image, image-content, and image-fallback through data-slot. Root exposes data-fit, data-position, data-radius, data-frame, optional data-ratio, optional data-fill, and Atom data-state.

Public variables:

  • --brick-image-fit
  • --brick-image-position
  • --brick-image-radius
  • --brick-image-frame-background
  • --brick-image-frame-border
  • --brick-image-frame-border-width
  • --brick-image-fallback-foreground
  • --brick-image-fallback-inset

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.