Image
Neo-brutalist image display component with IntersectionObserver lazy loading, fallback image support, and a full-screen preview modal featuring zoom, rotate, flip, and drag interactions — all wrapped in bold borders, hard shadows, and diagonal stripe placeholder backgrounds.
Demo
基础用法
大图预览(点击放大)
多图预览(左右切换)
懒加载
加载失败 + Fallback

Installation
pnpm dlx brutx-vue@latest add imageUsage
Basic Usage
Pass src and alt to render an image. Use fit to control how the image fills its container:
<script setup>
import { Image } from 'brutx-ui-vue'
</script>
<template>
<Image src="/photo.jpg" alt="Sample image" fit="cover" class="w-64 h-48" />
</template>Lazy Loading
Set loading="lazy" to defer image loading until the element enters the viewport via IntersectionObserver:
<template>
<Image src="/large-photo.jpg" alt="Lazy loaded image" loading="lazy" class="w-full h-64" />
</template>Fallback Image
When the primary image fails to load, the component automatically switches to the fallback URL:
<template>
<Image
src="/broken-url.jpg"
alt="Fallback demo"
fallback="/fallback.jpg"
class="w-64 h-48"
/>
</template>Image Preview
Enable preview and provide a previewSrcList to open a full-screen preview modal when clicking the image:
<script setup>
import { Image } from 'brutx-ui-vue'
const images = ['/photo1.jpg', '/photo2.jpg', '/photo3.jpg']
</script>
<template>
<div class="flex gap-4">
<Image
v-for="img in images"
:key="img"
:src="img"
:alt="img"
:preview="true"
:preview-src-list="images"
class="w-32 h-32"
/>
</div>
</template>The preview modal supports the following interactions:
- Zoom in / zoom out (via toolbar buttons, step controlled by
zoomRate) - Rotate left / right by 90°
- Horizontal flip
- Mouse drag to pan the image
ArrowLeft/ArrowRightto navigate between imagesEscapeto close the preview- Set
hideOnClickModaltotrueto close by clicking the backdrop
Custom Placeholder and Error Slots
Use the placeholder and error slots to customize loading and failure states:
<template>
<Image src="/photo.jpg" alt="Custom slots example" class="w-64 h-48">
<template #placeholder>
<div class="absolute inset-0 flex items-center justify-center bg-brutal-muted">
<span class="font-bold">Loading...</span>
</div>
</template>
<template #error>
<div class="absolute inset-0 flex items-center justify-center bg-brutal-destructive/10">
<span class="text-brutal-destructive font-bold">Failed to load</span>
</div>
</template>
</Image>
</template>Data Types
type ImageFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'| Value | Description |
|---|---|
'fill' | Stretches to fill the container without preserving aspect ratio |
'contain' | Scales to fit within the container while preserving aspect ratio |
'cover' | Scales to fill the container while preserving aspect ratio (may crop) |
'none' | Preserves the original size |
'scale-down' | Like contain, but never scales up beyond the original size |
API Reference
| Name | Type | Default | Description |
|---|---|---|---|
srcRequired | string | — | The required primary image URL. It is also the preview viewer’s only image when previewSrcList is empty. |
DetailsDeclared typestring Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
alt | string | undefined | "" | Alternative text passed to the native img element; describe the image for assistive technology. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
fit | "fill" | "none" | "cover" | "contain" | "scale-down" | undefined | "cover" | Sets the image’s CSS object-fit mode. |
DetailsDeclared type"fill" | "none" | "cover" | "contain" | "scale-down" | undefined Literal values
Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
previewSrcList | string[] | undefined | []Factory evaluated per instance | Provides the image URLs navigable in the preview viewer. Previous and next controls appear when the list has multiple entries. |
DetailsDeclared typestring[] | undefined Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
initialIndex | number | undefined | 0 | Sets the list index selected when the preview viewer opens. |
DetailsDeclared typenumber | undefined Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
hideOnClickModal | boolean | undefined | false | When enabled, clicking the preview backdrop closes the viewer and returns focus to the element that opened it. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
zoomRate | number | undefined | 1.2 | Sets the multiplier applied by each zoom-in or zoom-out action. |
DetailsDeclared typenumber | undefined Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
preview | boolean | undefined | false | Enables the image preview viewer with zoom, drag, and multi-image navigation. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
fallback | string | undefined | undefined | A fallback image URL tried after the primary image fails. The component enters its error state and emits error only if the fallback also fails. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
loading | "eager" | "lazy" | undefined | "eager" | Selects eager loading or lazy loading, which uses IntersectionObserver to defer loading until the image approaches the viewport. |
DetailsDeclared type"eager" | "lazy" | undefined Literal values
Default value details
Sourcepackages/ui/src/components/image/Image.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@close | [] | Emitted when the preview viewer closes; the component then attempts to restore focus to the previously active element. |
DetailsDeclared type[] Sourcepackages/ui/src/components/image/Image.vue | ||
@error | [event: Event] | Emitted with the final native image error event when both the primary and fallback images fail to load. |
DetailsDeclared type[event: Event] Sourcepackages/ui/src/components/image/Image.vue | ||
@load | [event: Event] | Emitted with the native image event when an image loads successfully, including a successful fallback image. |
DetailsDeclared type[event: Event] Sourcepackages/ui/src/components/image/Image.vue | ||
@show | [] | Emitted when the preview viewer opens. |
DetailsDeclared type[] Sourcepackages/ui/src/components/image/Image.vue | ||
@switch | [index: number] | Emitted with the new image-list index after the preview viewer switches images. |
DetailsDeclared type[index: number] Sourcepackages/ui/src/components/image/Image.vue | ||
| Name | Signature or type | Description |
|---|---|---|
#placeholder | {} | Renders custom content while the image is loading; the built-in loading placeholder is used when omitted. |
DetailsDeclared type{}Sourcepackages/ui/src/components/image/Image.vue | ||
#error | {} | Renders custom error content after the image and fallback fail; the built-in failure placeholder is used when omitted. |
DetailsDeclared type{}Sourcepackages/ui/src/components/image/Image.vue | ||
Accessibility
- Keyboard Navigation: The preview modal supports
Escapeto close andArrowLeft/ArrowRightto navigate between images - ARIA Attributes: Close, previous, and next buttons in the preview modal all include
aria-labelattributes. Always provide meaningfulalttext for screen readers and when images fail to load - Focus Management: The preview modal uses reka-ui's
FocusScopecomponent withtrappedandloopmodes, preventing focus from escaping the modal
FAQ
Q: The image doesn't appear when loading="lazy" is set?
A: Lazy loading relies on IntersectionObserver, which requires the component container to have definite dimensions (set via class or a parent container). If the container has zero dimensions, the IntersectionObserver callback will never fire.
Q: How do I navigate between images in the preview?
A: You need to pass a previewSrcList array. Inside the preview modal, you can navigate using the arrow buttons or keyboard arrow keys. If the list contains one or zero items, the navigation buttons are hidden.
Q: What happens if the fallback image also fails to load?
A: When the fallback image also fails, the component enters its error state, displays the error slot content (or the default error placeholder), and emits the error event.