Image
Image is an enhanced image component with a self-contained zoom-and-pan preview viewer, custom actions, and various display styles. Preview is powered by a Base UI dialog with FLIP open/close transitions, deep zoom, and gallery navigation — it no longer wraps Ant Design's Image.
import { Image } from '@lobehub/ui';Default
Gallery
Wrap multiple Image components in Image.PreviewGroup to preview them together, with arrow buttons, a counter, and ←/→ keyboard navigation.
Fallback
Custom Actions
Dual Source Preview
preview.src lets the thumbnail stay lightweight while the viewer opens instantly against it, then swaps in a higher-resolution image in place once it finishes loading — no layout jump.
Deep Zoom
Ctrl/Cmd + wheel, double-click, or the toolbar's zoom buttons zoom in past the fitted size for pixel-level detail; drag to pan once zoomed. preview.maxScale raises the zoom ceiling for large source images.
Default Zoom
preview.defaultZoom picks the scale the viewer opens at. The default, auto, opens an image at its natural size when it is at most preview.autoZoomThreshold times the fitted size, and falls back to the fitted size beyond that. This keeps screenshots and text-bearing images legible on open — fitting a 2560px-wide screenshot into a 1400px viewport halves its text — while a photo many times the viewport still opens whole rather than showing a corner of itself.
Opening above the fitted size also means the image overflows the viewport, so it is immediately pannable. Scrolling down zooms back out to the fitted size before the next scroll dismisses the viewer.
Toolbar Addon
preview.toolbarAddon appends custom controls to the end of the preview toolbar — here, a button that opens the original file in a new tab.
Interaction Model
The preview viewer opens with a FLIP transition from the clicked thumbnail's on-screen position and returns to it on close (or fades, if the thumbnail is no longer available or prefers-reduced-motion is set).
Zoom & pan
- Scrolling up always zooms in, at any scale. Scrolling down zooms out until the fitted size, which is the zoom floor.
- Ctrl/Cmd + wheel (trackpad pinch) zooms from any state, in either direction.
- The toolbar zoom buttons zoom around the viewport center; the wheel zooms around the cursor.
- The toolbar's expand/shrink button toggles between the fitted size and 100%, and is disabled for an image small enough that the two coincide. The toolbar percentage beside it is a readout only.
0resets to the opening state, which also clears rotation and flips.- Double-click toggles between fitted and a zoomed-in target scale.
- Dragging pans whenever the image overflows the viewport, clamped so it can't be dragged past its edges. An image that fits entirely stays centered — there is nothing off-screen to reveal.
Closing
- Scrolling down while already at the fitted size closes the viewer once the accumulated scroll passes a threshold — the dismiss gesture is the continuation of zooming out. A large zoom-out overshoot re-arms after ~300ms of wheel idle rather than closing immediately, and a rotated or flipped image is never dismissed this way.
- Clicking the backdrop, the close button, or pressing Esc while the viewer is untouched closes immediately. "Untouched" means still at the opening scale with no rotation or flip — so an image that opened at 100% under
defaultZoomstill closes on the first Esc or click. - Clicking the image itself closes after a short delay unless a second click arrives in time (in which case it double-click-zooms instead of closing).
- Esc is layered: once zoomed away from the opening scale, or rotated or flipped, the first Esc resets; only a second Esc closes.
Gallery
- Inside
Image.PreviewGroup, the arrow buttons, on-screen counter, and←/→keys navigate between images; rotation and flips clear on every switch, and each image lands at its owndefaultZoomscale. - Outside a gallery (a single previewable
Image),←/→are left alone for the browser/page to handle.
Breaking Changes
The preview viewer was rewritten from scratch on top of a Base UI dialog and no longer wraps rc-image / Ant Design's Image preview. The following antd/rc-image passthrough is no longer supported:
PreviewGroup'sitemsprop — build the group fromImagechildren instead.minScale,onVisibleChange, and other rc-imageImagePreviewTyperender/lifecycle props.- Any other undocumented antd
Image/rc-imagepreview props that used to pass through via...rest.
preview now only accepts boolean | { src?, defaultZoom?, autoZoomThreshold?, maxScale?, onOpenChange?, toolbarAddon? } (see below).
In apps without an app-level
ToastHost(see@lobehub/ui/base-ui), a copy/download toast fired after the viewer has already closed is dropped rather than shown standalone. This is an accepted limitation — mount aToastHostat the app root to avoid it.
APIs
Image
actionsnull | string | number | bigint | false | true | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode>alwaysShowActionsbooleanclassNames{ image?: string; wrapper?: string; }heightstring | numberisLoadingbooleanmaxHeightstring | numberDefaults to
"100%".maxWidthstring | numberDefaults to
"100%".minHeightstring | numberminWidthstring | numberobjectFit'contain' | 'cover'Defaults to
"cover".previewfalse | true | ImagePreviewOptionsrefnull | ((instance: HTMLImageElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) & RefObject<HTMLDivElement | null> | ((instance: HTMLImageElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) & ((instance: HTMLDivElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | RefObject<HTMLImageElement | null> & RefObject<HTMLDivElement | null> | RefObject<HTMLImageElement | null> & ((instance: HTMLDivElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES])Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
sizestring | numberstyles{ image?: CSSProperties; wrapper?: CSSProperties; }variant'outlined' | 'borderless' | 'filled'Defaults to
"filled".widthstring | number
Also accepts all native HTML and ARIA attributes.
Additional props are spread onto the underlying
<img>element.
PreviewGroup
| Property | Description | Type | Default |
|---|---|---|---|
| enable | Whether to enable the preview group | boolean | true |
| preview | Preview options for the whole group | boolean | ImagePreviewOptions | - |
Each
Imageresolves its ownpreviewagainst the group's: an option object is merged over the group's (per-image keys win), and a per-imagepreviewof any kind takes precedence over the group's.preview={false}on the group is therefore a default for children that don't set their own — a child passingpreview={false}opts out of an enabled group, and a child passing an options object opts back into a disabled one.
ImagePreviewOptions
| Property | Description | Type | Default |
|---|---|---|---|
| src | Higher-resolution source swapped in after the viewer opens with src | string | - |
| defaultZoom | Scale the viewer opens at. fit always shows the whole frame, actual always opens at 100%, and auto opens at 100% only when the image is within autoZoomThreshold of the fitted size | 'auto' | 'actual' | 'fit' | 'auto' |
| autoZoomThreshold | How many times the fitted size an image may be and still open at 100% under defaultZoom: 'auto'. Ignored by the other policies | number | 2 |
| maxScale | Maximum zoom scale relative to the fitted size. Raised automatically when defaultZoom resolves above it, so the opening scale is always reachable | number | 8 |
| onOpenChange | Called when the preview viewer opens or closes | (open: boolean) => void | - |
| toolbarAddon | Additional content appended to the preview toolbar | ReactNode | - |