In React Native Web, what DOM does an Image render, and how do resizeMode and its accessibility label map onto it?
answer
- not a single img tag
- background-image on an inner div
- resizeMode becomes background-size
- an invisible img keeps the context menu
- alt comes from the aria label
basics
~20 sReact Native Web renders Image as a div holding a background-image layer sized by resizeMode, plus an invisible img whose alt comes from aria-label or accessibilityLabel, so the context menu and assistive technology still see an image.
solid answer
~40 s`Image` in `react-native-web` is not a bare `<img>`. It renders an outer `View` (a `div` with `overflow: hidden`), an absolutely filled inner `div` that shows the picture as a CSS `background-image`, and a hidden `<img>` with `opacity: 0` stacked in the same box. `resizeMode` maps to `background-size`: `cover` (the default) and `contain` directly, `stretch` to `100% 100%`, `center` and `repeat` to `auto`. The hidden `img` gets `alt` from `aria-label` or `accessibilityLabel` (empty otherwise) and `draggable={false}` unless you set it, and it exists so right-click "save image" and similar browser features still work. `blurRadius` and `tintColor` become CSS and SVG filters, and children throw in development: use `ImageBackground`.
go deeper
Recall that Image still takes source and resizeMode on the web, and that an accessible label is needed for meaningful images.
Describe the rendered tree: outer div, background-image layer sized by resizeMode, and the invisible img that carries alt and the browser's image features.
Anticipate the consequences for browser tests, CSS rules that target img, accessibility audits of empty alt, zero-size remote images, and when to use ImageBackground.
Judge whether the web build's image needs (lazy loading, responsive sources, SEO) justify a web-specific image component rather than relying on the portable one.
## Not an img tag Web developers expect `<Image>` to become `<img>`. In **React Native Web** it renders a small tree instead: 1. An **outer `View`** (a `div`) with `overflow: hidden`, `flexBasis: 'auto'` and `zIndex: 0`, carrying your `style`, `aria-label`, `testID` and layout. 2. An **inner `div`**, absolutely filling the outer one, that shows the picture as a CSS **`background-image: url(...)`**. 3. A **hidden `<img>`**, also absolutely filling the box with `opacity: 0` and `zIndex: -1`, pointing at the same URL. 4. When `tintColor` is set, an inline **SVG filter** used to recolour the image. The background-image approach lets React Native's `resizeMode` values map onto CSS background sizing. The invisible `img` exists so the browser still treats the area as an image. ## resizeMode on the web | `resizeMode` | CSS on the inner div | |---|---| | `cover` (default) | `background-size: cover` | | `contain` | `background-size: contain` | | `stretch` | `background-size: 100% 100%` | | `center` | `background-size: auto` (scaled down if larger than the box) | | `repeat` | `background-repeat: repeat`, tile at natural size (scaled down if larger than the box) | | `none` | `background-size: auto`, positioned at the origin | Setting `resizeMode` inside `style` still works but warns in development that it is deprecated; pass it as a prop. ## Accessibility and the browser's image features - The hidden `img` gets **`alt`** from `aria-label`, falling back to `accessibilityLabel`, and to an empty string when neither is set. An empty `alt` tells assistive technology the image is decorative, so a meaningful picture **needs a label**. - The outer `div` also receives `aria-label`. - The hidden `img` is what the user right-clicks: **"save image as"** and **"copy image"** work because it is a real image element on top of the painted background. - `draggable` defaults to `false` on that `img`, so a drag does not start the browser's native image drag unless you opt in. ## Sizing and loading - The outer `View` takes `width` and `height` from `source` when the source object includes them, or from a static asset's registered dimensions. A **remote URI with neither source dimensions nor a style size has no intrinsic height and renders zero pixels tall**, just as on native. - Loading goes through an internal loader with states idle, loading and loaded. `defaultSource` is shown while the main source loads, and `onLoadStart`, `onLoad`, `onError` and `onLoadEnd` fire from it. - `Image.getSize`, `Image.prefetch` and `Image.queryCache` are implemented on the web. ## Effects and restrictions - **`blurRadius`** becomes a CSS `blur(...)` filter and **`tintColor`** an SVG colour filter on the displayed layer. - `shadow*` styles are neutralised on the `Image` itself; wrap it in a `View` for a shadow. - **Children are not allowed**: in development, `Image` throws "The <Image> component cannot contain children", pointing you to `ImageBackground` or absolute positioning. ## Comparing it with the native component On iOS and Android, `Image` is a native image view that decodes and scales the bitmap itself, and `resizeMode` is a property of that view. On the web there is no such view, so React Native Web composes the behaviour from standard browser features: - **Scaling** comes from CSS background sizing rather than from the image element. - **Loading state** comes from its own loader rather than from the view. - **Accessibility** comes from the hidden element's `alt` rather than from an accessibility label on a native view. The public props stay the same, which is the point of the library; only the mechanism underneath changes, and that mechanism is what leaks into tests, audits and CSS. ## Why this matters in practice - Browser tests that look for `img[src]` find the hidden element, but visual checks look at a background image. - A CSS rule or an extension that targets `img` elements affects the invisible layer, not what is painted. - Accessibility audits flag meaningful images without labels because the generated `alt` is empty. ```tsx import { Image } from 'react-native'; <Image source={{ uri: 'https://example.com/cat.jpg', width: 320, height: 200 }} resizeMode="contain" aria-label="A cat asleep on a keyboard" /> // => div[aria-label] > div(background-image, background-size: contain) + img[alt="A cat asleep on a keyboard"] ```
- In React Native Web, why might an accessibility audit flag every Image in an app as decorative?Because the hidden `img` that React Native Web renders takes its `alt` from `aria-label` or `accessibilityLabel`, and falls back to an empty string. An empty `alt` marks an image as decorative. Meaningful images need a label prop; purely decorative ones can keep the empty default.
- In React Native Web, what happens if you put a Text inside an Image to caption it?In development the `Image` throws, saying it cannot contain children and suggesting `ImageBackground` or absolute positioning. `ImageBackground` renders the image as an absolutely filled layer behind its children, which is the supported way to overlay content.
saying these in an interview costs you the question
- React Native Web renders Image as a single img element with object-fit.
- The alt attribute is generated from the image file name.
- resizeMode has no effect on the web.
- Right-click save does not work because the picture is a CSS background.
- Placing children inside an Image works on the web.