Image
Headless image with loading states, candidate fallback chains, and deferred loading.
|
|
| Package |
@vizejs/ui/image |
| Maturity |
stable |
| Own the source |
vize lib pull image |
| Requires |
context, measure |
| Aliases |
image, img, picture, lazy image, image fallback |
| Covers |
HTML img, Radix Avatar image loading status, Chakra UI Image, Next.js Image placeholder |
Usage
import { ImageContent, ImageFallback, ImagePlaceholder, ImageRoot } from "@vizejs/ui/image";
Or copy the source into your project with vize lib pull image (see Source Distribution).
API
ImageContent
Source: src/families/media/image/image-content.vue
Props
| Prop |
Type |
Default |
Description |
alt (required) |
string |
required |
Native alternative text. Pass "" for decorative images. |
srcset |
string |
undefined |
Responsive candidates for the first source. Dropped once the chain falls back, so a failing srcset cannot shadow later candidates. |
sizes |
string |
undefined |
Native sizes paired with srcset. |
width |
number | string |
undefined |
Intrinsic width used by the browser to reserve layout space. |
height |
number | string |
undefined |
Intrinsic height used by the browser to reserve layout space. |
loading |
ImageLoading |
"lazy" |
Native loading policy. |
decoding |
ImageDecoding |
"async" |
Native decoding policy. |
fetchPriority |
ImageFetchPriority |
undefined |
Native fetch-priority hint. |
crossOrigin |
ImageCrossOrigin |
undefined |
Native CORS policy. |
referrerPolicy |
ImageReferrerPolicy |
undefined |
Native referrer policy. |
Exposed
| Member |
Type |
Description |
status |
ImageStatus |
Current loading lifecycle state. |
src |
string | undefined |
Source currently attached to the native image, or undefined while idle or failed. |
candidateIndex |
number |
Zero-based position of the attached candidate in the candidate chain, or -1. |
candidateCount |
number |
Number of safe candidates in the chain. |
element |
HTMLImageElement | null |
Rendered native image element, or null after every candidate failed. |
ImageFallback
Source: src/families/media/image/image-fallback.vue
Slots
| Slot |
Slot props |
Description |
default |
ImagePartSlotState |
Fallback content rendered after every candidate failed or none was safe. |
Exposed
| Member |
Type |
Description |
element |
HTMLSpanElement | null |
Rendered fallback element while visible. |
visible |
boolean |
Whether the fallback is rendered. |
ImagePlaceholder
Source: src/families/media/image/image-placeholder.vue
Props
| Prop |
Type |
Default |
Description |
delay |
number |
0 |
Milliseconds the image must stay pending before the placeholder renders, so cached images do not flash a skeleton. Positive delays render nothing on the server. |
Slots
| Slot |
Slot props |
Description |
default |
ImagePartSlotState |
Placeholder content such as a skeleton, blur-up preview, or spinner. |
Exposed
| Member |
Type |
Description |
element |
HTMLSpanElement | null |
Rendered placeholder element while visible. |
visible |
boolean |
Whether the placeholder is rendered. |
ImageRoot
Source: src/families/media/image/image-root.vue
Props
| Prop |
Type |
Default |
Description |
src |
ImageSource | null |
undefined |
Image source or ordered candidate chain. Each failed candidate advances to the next safe one; unsafe or malformed candidates are skipped and never rendered. |
defer |
boolean |
false |
Wait until the root intersects the viewport before attaching any source. Complements native loading="lazy" for background-critical or custom scroll roots. |
rootMargin |
string |
"200px" |
Intersection margin used while defer waits for visibility. |
allowInsecure |
boolean |
false |
Permit unencrypted http: candidates for local development. |
Events
| Event |
Payload |
Description |
load |
[nativeEvent: Event | null, src: string] |
Fired after the attached candidate loads. nativeEvent is null for pre-hydration loads. |
error |
[nativeEvent: Event | null, src: string] |
Fired after one candidate fails, before the next candidate is attached. |
statusChange |
[status: ImageStatus, previous: ImageStatus, reason: ImageStatusChangeReason] |
Fired after every distinct status transition with the cause of the transition. |
Slots
| Slot |
Slot props |
Description |
default |
ImageSlotState |
Compound Image parts. Receives the current loading lifecycle state. |
Exposed
| Member |
Type |
Description |
status |
ImageStatus |
Current loading lifecycle state. |
src |
string | undefined |
Source currently attached to the native image, or undefined while idle or failed. |
candidateIndex |
number |
Zero-based position of the attached candidate in the candidate chain, or -1. |
candidateCount |
number |
Number of safe candidates in the chain. |
element |
Element | null |
Rendered root element. |
retry |
() => boolean |
Restart the candidate chain from the first safe source. Reports whether a retry started. |
Behavior
Normative state x input -> outcome table for image-root.vue, image-content.vue,
image-placeholder.vue, and image-fallback.vue (@vizejs/ui/image). Every row
is proven by the named test. A row without a passing test is a contract violation.
The lifecycle is idle -> loading -> loaded | error. ImageRoot owns the source
candidate chain and the lifecycle; ImageContent renders the native <img>,
ImagePlaceholder renders while pending, and ImageFallback renders after the
chain is exhausted. Every part mirrors the lifecycle through data-status.
| ID |
State |
Input |
Outcome |
Evidence |
| I1 |
source present |
render |
root is loading; native image receives the first safe candidate, srcset/sizes, loading="lazy", decoding="async", and hints |
renders a loading native image with placeholder, native attributes, and no fallback |
| I2 |
loading |
native load |
lifecycle becomes loaded, placeholder unmounts, load emits (event, src), statusChange reports load |
load settles the lifecycle, hides the placeholder, and emits load |
| I3 |
loading |
native error |
the next safe candidate is attached without srcset; after the last failure the image unmounts and the fallback renders |
advances through the candidate chain and renders the fallback after the last failure |
| I4 |
missing or unsafe |
render |
lifecycle is error; no <img> or unsafe URL is rendered; http: requires allowInsecure |
missing and unsafe sources render the fallback without forwarding a source |
| I5 |
settled |
src change / retry() |
a different chain restarts at the first candidate (source); an equal chain keeps state; retry() restarts or reports false |
source replacement and retry restart the chain |
| I6 |
defer |
render / intersect |
lifecycle stays idle without src until the root intersects (rootMargin), then loads and stops observing |
deferred images stay idle until visible and fall back to eager without observers |
| I7 |
defer, no IO |
mount |
without IntersectionObserver the source attaches on mount |
deferred images stay idle until visible and fall back to eager without observers |
| I8 |
defer |
defer becomes false |
the source attaches immediately |
turning defer off attaches the source immediately |
| I9 |
placeholder delay |
pending longer / shorter |
positive delay renders the placeholder only after the delay and never after the image settles |
delayed placeholders wait before rendering and never render after settling |
| I10 |
hydration race |
image settled before hydration |
a complete image with pixels is loaded; a complete image is decoded to settle loaded or error; events report null |
reads images that settled before hydration attached listeners |
| I11 |
exposed instance |
read |
root exposes status, attached source, candidate index/count, element, and retry() |
exposes typed lifecycle state and live parts |
| I12 |
missing provider |
setup |
compound parts fail closed with the shared context diagnostic |
compound parts require a matching root provider |
| I13 |
candidate policy |
resolveImageCandidates() |
trims, filters by the shared media-source policy, de-duplicates in order, and freezes the chain |
resolves safe, de-duplicated candidate chains |
| I14 |
SSR |
isolated requests |
loading, error, idle, and delayed-placeholder markup is byte-identical and never contains unsafe candidates |
renders byte-identical loading image markup across isolated SSR requests |
| I15 |
SSR |
render |
fallback, idle, and delayed-placeholder states are deterministic on the server |
renders fallback, idle, and delayed-placeholder states deterministically on the server |
| I16 |
SSR / hydration |
hydrate |
server markup hydrates without warnings or node replacement |
hydrates server image markup without warnings or node replacement |
| I17 |
types |
compile |
lifecycle, reasons, candidate chains, slot state, and exposes are closed and read-only |
image.types.test-d.ts |
Styling hooks: data-status on every part, data-deferred on the root, and
data-candidate on the image. No CSS ships with the primitive; hide the image
while data-status="loading" if a placeholder should occupy the same box.