Liking cljdoc? Tell your friends :D

x-image

A stateless, themeable image component that reserves layout space via an optional aspect ratio, shows a skeleton shimmer while loading, fades in on successful load, and renders a default or slotted fallback on error.


Tag

<x-image src="/photo.jpg" alt="A description"></x-image>

Attributes

AttributeTypeDefaultDescription
srcURLImage URL. Sanitized against a protocol whitelist
altstringAlternative text for screen readers. Required unless decorative
decorativebooleanfalseMarks the image as purely decorative; sets alt="" + aria-hidden
ratio"W:H" | autoautoAspect ratio, e.g. 16:9, 1:1, 4:3. Prevents layout shift
fitenum"cover"cover contain fill none scale-down
positionstring"center"CSS object-position value
loadingenum"lazy"lazy or eager (forwarded to inner <img>)

Accepted src protocols: http:, https:, data:, blob:, plus relative URLs. javascript: and other schemes are silently dropped.

ratio format: W:H or W/H with positive numbers (integer or decimal). Invalid values log a console warning once per element and fall back to intrinsic sizing.


Properties

PropertyTypeReflects attributeNotes
srcstringsrc
altstringalt
decorativebooleandecorativePresent-as-true
ratiostringratio
fitstringfit
positionstringposition
loadingstringloading
naturalWidthnumberRead-only; 0 before load
naturalHeightnumberRead-only; 0 before load
statestringRead-only; loading | loaded | error

Events

EventBubblesComposedCancelableDetail
x-image-loadyesyesno{ src, naturalWidth, naturalHeight }
x-image-erroryesyesno{ src }

Events fire once per successful transition into their respective state. Changing src resets state to loading and will fire a new event when the new image resolves.


Slots

SlotDescription
errorCustom fallback content shown on failure
<x-image src="/missing.png" alt="Fallback demo">
  <div slot="error">Image unavailable. <a href="/contact">Report</a></div>
</x-image>

When no slot="error" content is provided, a default ⚠ Image unavailable message is shown.


Parts

PartDescription
frameOuter aspect-ratio container
shimmerSkeleton placeholder overlay
imageInner <img> element
errorError-state container
error-defaultDefault fallback wrapper
error-glyphDefault glyph <span>
error-textDefault error text <span>

CSS Custom Properties

VariableDefaultDescription
--x-image-radiusvar(--x-radius-md, 8px)Frame border radius
--x-image-bgvar(--x-color-surface, #f3f4f6)Frame background / placeholder
--x-image-border0Frame border shorthand
--x-image-shimmer-colorvar(--x-color-border, rgba(0,0,0,.08))Shimmer base colour
--x-image-shimmer-highlightrgba(255,255,255,.65)Shimmer sweep highlight
--x-image-shimmer-duration1.5sShimmer animation duration
--x-image-fade-durationvar(--x-transition-duration, 200ms)Fade-in duration
--x-image-fade-easingvar(--x-transition-easing, ease)Fade-in easing
--x-image-textvar(--x-color-text-muted, …)Error text colour
--x-image-font-familyvar(--x-font-family, …)Error text font
--x-image-font-sizevar(--x-font-size-sm, 0.875rem)Error text size
--x-image-error-gapvar(--x-space-xs, 6px)Gap between glyph and text

Dark-mode variants for --x-image-bg, --x-image-shimmer-*, and --x-image-text are applied automatically via @media (prefers-color-scheme: dark).


Accessibility

  • When not decorative, the host receives role="img" and forwards alt to the inner <img>.
  • When decorative, the host receives aria-hidden="true" and the inner <img> gets alt="".
  • Omitting alt on a non-decorative image logs a one-time console warning.
  • The error region carries role="img" with an aria-label derived from alt (or "Image failed to load").
  • Shimmer is marked aria-hidden="true".
  • Shimmer animation and fade-in are disabled under @media (prefers-reduced-motion: reduce).

Stateless rendering

The component is fully re-derived from HTML attributes on every change. No internal state beyond cached DOM refs and the current load-state marker. The underlying <img> has no abort primitive; when src changes, the previous request is superseded by browser semantics, and only the most recently set src dispatches events.

naturalWidth and naturalHeight return 0 before the image has finished loading and reflect the inner <img>'s natural dimensions afterwards.


Examples

Fixed aspect ratio

<x-image src="/hero.jpg" alt="Team photo" ratio="16:9"></x-image>

Decorative image

<x-image src="/pattern.svg" decorative ratio="1:1"></x-image>

Custom error fallback

<x-image src="/may-404.jpg" alt="Preview" ratio="4:3">
  <div slot="error">Preview unavailable</div>
</x-image>

Listening for load

document.querySelector('x-image').addEventListener('x-image-load', e => {
  console.log('loaded', e.detail.src, e.detail.naturalWidth, e.detail.naturalHeight);
});

ClojureScript (hiccup renderer)

[:x-image {:src "/photo.jpg" :alt "Profile" :ratio "1:1" :fit "cover"}]

[:x-image {:src      "/bg.png"
           :decorative true
           :ratio    "16:9"}]

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close