Files
zeekayandHanzo Dev 751ef5c778 rename the framework to @hanzo/gui and the loader to @hanzogui/loader
Both old names are owned by a different npm account (artemis-prime), so
publishing them returns 403 — which is how this surfaced: the 8.0.0 run
shipped @hanzogui/logo and @hanzogui/demos depending on [email protected], a
version that cannot be published and therefore does not exist. Those two
were uninstallable.

@hanzo/gui and @hanzogui/* are ours, so the framework now carries the name
it is imported by everywhere downstream, and the loader moves under the
scope we control.

The rewrite is limited to package references. `DEBUG?.startsWith('hanzogui')`
is a log-namespace filter and join(dir, 'hanzogui') is a path — rewriting
either would change behaviour, so both are untouched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 20:23:18 -07:00

324 lines
7.7 KiB
Plaintext

---
title: Image
description: A pure, lightweight Image component with Gui style props
name: image
component: Image
package: image
demoName: Image
---
<HeroContainer noPad>
<ImageDemo />
</HeroContainer>
```tsx hero template=Image
```
<Highlights
features={[
'Supports SSR.',
'Works on native and web.',
'Accepts Gui style props.',
'Pluggable architecture with createImage for expo-image and more.',
]}
/>
## Installation
Image is already installed in `hanzogui`, or you can install it independently:
```bash
npm install @hanzogui/image
```
## Usage
Use the `src` prop for the image URL:
```tsx
import { Image } from '@hanzo/gui'
export default () => (
<Image src="https://example.com/photo.jpg" width={200} height={200} />
)
```
You can also use `objectFit` to control how the image fits its container:
```tsx
<Image src="https://example.com/photo.jpg" width="100%" height={300} objectFit="cover" />
```
### Sizing on native
`width` and `height` are Gui layout props. On native, they become React Native
Image styles. Remote images must resolve to a nonzero layout size, so use fixed
dimensions or place percentage-sized images inside a parent with defined dimensions:
```tsx
<View width={320} height={200}>
<Image
src="https://example.com/photo.jpg"
width="100%"
height="100%"
objectFit="cover"
/>
</View>
```
Gui converts a string `src` to `source={{ uri: src }}` on native. Layout
dimensions stay in `style`; they are not copied into the native source metadata.
React Native `source` objects remain supported for migration, but `src` is preferred.
## Using with expo-image
For better performance and features like blurhash placeholders and transitions,
you can use `createImage` to create a custom Image component with expo-image:
```tsx
import { Image as ExpoImage } from 'expo-image'
import { createImage } from '@hanzogui/image'
export const Image = createImage({
Component: ExpoImage,
resizeModePropName: 'contentFit',
objectPositionPropName: 'contentPosition',
})
```
Now you can use all expo-image props alongside Gui's unified API:
```tsx
const blurhash = '|rF?hV%2WCj[ayj[a|j[az...'
export default () => (
<Image
src="https://example.com/photo.jpg"
width={200}
height={300}
objectFit="cover"
placeholder={{ blurhash }}
transition={300}
/>
)
```
### createImage Options
<SimpleTable
headers={['Option', 'Type', 'Default', 'Description']}
rows={[
[
'Component',
'`ComponentType`',
'-',
'The underlying image component (expo-image, react-native-fast-image, etc.)',
],
[
'resizeModePropName',
'`string`',
"`'resizeMode'`",
"The prop name for resize mode. expo-image uses `'contentFit'`",
],
[
'objectPositionPropName',
'`string`',
'`undefined`',
"The prop name for object position. expo-image uses `'contentPosition'`",
],
[
'mapObjectFitToResizeMode',
'`function`',
'Default mapper',
"Custom function to map `objectFit` values to the component's resize mode",
],
[
'transformSource',
'`function`',
'Default transformer',
'Custom function to transform source props',
],
]}
/>
## Accessibility
Always provide an `alt` attribute describing the image content. For decorative images, use an empty string (`alt=""`).
```tsx
// meaningful image
<Image
src="/team-photo.jpg"
alt="The Gui team at React Conf 2024"
width={400}
height={300}
/>
// decorative image
<Image
src="/decorative-bg.jpg"
alt=""
width={400}
height={300}
/>
```
On React Native, use `accessible` and `accessibilityLabel` for screen reader support. See the [React Native Accessibility docs](https://reactnative.dev/docs/accessibility) for details.
```tsx
<Image
src="/avatar.jpg"
accessible
accessibilityLabel="User profile photo"
width={64}
height={64}
/>
```
## API Reference
### Image
Extends View with [Gui props](/docs/intro/props), plus:
<PropsTable
data={[
{
name: 'src',
type: 'string | number',
description:
'The image URL or native require() result. Preferred over `source` for better web alignment.',
},
{
name: 'alt',
type: 'string',
description:
'Alternative text describing the image for accessibility. Use empty string for decorative images.',
},
{
name: 'objectFit',
type: "'cover' | 'contain' | 'fill' | 'none' | 'scale-down'",
description:
'How the image should be resized to fit its container. Maps to CSS object-fit on web and resizeMode on native.',
},
{
name: 'objectPosition',
type: 'string',
description:
'How the image should be positioned within its container. On native, requires expo-image or similar for full support.',
},
{
name: 'source',
type: 'ImageSourcePropType',
description:
'Deprecated React Native source prop. It remains supported during migration; prefer `src`.',
},
{
name: 'resizeMode',
type: 'ImageResizeMode',
description: 'Deprecated. Use `objectFit` instead.',
},
]}
/>
### Web-only Props
These props pass through to the native `<img>` element on web:
<PropsTable
data={[
{
name: 'loading',
type: "'lazy' | 'eager'",
description:
'Lazy load images below the fold. Use eager (default) for above-the-fold images.',
},
{
name: 'decoding',
type: "'async' | 'sync' | 'auto'",
description:
'Hint for how the browser should decode the image. Use async for non-blocking decode.',
},
{
name: 'fetchPriority',
type: "'high' | 'low' | 'auto'",
description:
'Hint for fetch priority. Use high for LCP (largest contentful paint) images.',
},
{
name: 'srcSet',
type: 'string',
description:
'Comma-separated list of image sources with width descriptors for responsive images.',
},
{
name: 'sizes',
type: 'string',
description:
'Media conditions describing the image display size, used with srcSet.',
},
{
name: 'crossOrigin',
type: "'anonymous' | 'use-credentials'",
description: 'CORS setting for the image request.',
},
{
name: 'referrerPolicy',
type: 'string',
description: 'Referrer policy for the image request.',
},
]}
/>
### Accessibility Props
<PropsTable
data={[
{
name: 'alt',
type: 'string',
description:
'Alternative text for screen readers. Required for meaningful images, use empty string for decorative.',
},
{
name: 'accessible',
type: 'boolean',
description: 'Native only. Marks the image as an accessible element.',
},
{
name: 'accessibilityLabel',
type: 'string',
description:
'Native only. Label read by screen readers. Use with accessible={true}.',
},
{
name: 'aria-label',
type: 'string',
description: 'Overrides alt as the accessible name. Prefer using alt instead.',
},
{
name: 'aria-describedby',
type: 'string',
description: 'References an element providing extended description.',
},
{
name: 'aria-hidden',
type: 'boolean',
description: 'Hides the image from assistive technology. Alternative to alt="".',
},
{
name: 'role',
type: 'string',
description:
"Set to 'presentation' or 'none' for decorative images, or 'img' (default).",
},
]}
/>
<Notice theme="green">
Web props like `loading`, `srcSet`, and `fetchPriority` only apply on web. On native,
use expo-image via `createImage` for advanced features like blurhash placeholders and
priority loading.
</Notice>