> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ImageInput

> Image selection, preview, and caller-owned upload actions.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`ImageInput` combines an image preview, a native file picker, and upload, remove, or abort actions. `onFileSelect` fires when a file is selected. Your application validates and uploads the file, owns upload progress and cancellation, and supplies the preview URL through `src`.

<StoryEmbed storyId="ui-input-imageinput--display" title="Choose, preview, and remove an image" height={140} />

## Usage

```tsx theme={null}
import { useState } from 'react';
import { ImageInput } from 'twenty-ui/components/input';

export const WorkspaceImage = () => {
  const [preview, setPreview] = useState<{
    src?: string;
    reader?: FileReader;
  }>({});

  return (
    <ImageInput
      helperText="Choose a square image for your workspace."
      src={preview.src}
      onFileSelect={(file) => {
        const reader = new FileReader();
        setPreview((current) => ({ src: current.src, reader }));
        reader.onload = () => {
          setPreview((current) => {
            if (current.reader !== reader) {
              return current;
            }

            return { src: reader.result?.toString() };
          });
        };
        reader.readAsDataURL(file);
      }}
      onRemove={() => setPreview({})}
    />
  );
};
```

The example keeps the current preview while reading a replacement and ignores reads from removed or superseded selections.

## Selection and preview

The preview and Upload button open the same native file picker. `onFileSelect` receives the selected `File`; it does not start an upload itself. Canceling or returning an empty selection leaves the current image unchanged. The file input clears after selection so the same file can be selected again, and the callback's `File` remains usable.

Front components support native selection and readable `File` contents. The SDK-built React and Preact flows are verified in Chromium with pointer, Enter and Space activation. The picker opens only from a trusted click inside the component. Worker-created object URLs assigned to an image `src` support previews.

`accept` defaults to `image/*` and filters the file picker. Validate allowed formats, dimensions, and size in your application. This callback-driven selector does not retain a file for native form submission. Its action buttons use `type="button"`, so they do not submit a surrounding form.

An empty or failed image shows a placeholder. Changing `src` retries the preview, including after an earlier image failed to load. Removal calls `onRemove`; update `src` after your application removes the image. The application owns local preview URLs and revokes worker-created object URLs when they are no longer needed. The renderer owns cleanup of its host preview URLs.

## Root and file input props

`className`, `style`, and `ref` apply to the root div. The default root ref receives an `HTMLDivElement`; use `inputRef` for the hidden file input. Use `render={<div ... />}` to supply native root attributes or event handlers. Keep that root non-interactive, since the module already contains buttons. `dir` applies to both the root and file input; use `dir="rtl"` for right-to-left layout.

Native file input attributes are top-level props, including `accept`, `capture`, `name`, `id`, `title`, `form`, `required`, accessible attributes, data attributes, and event handlers. They apply to the hidden input. `inputRef` receives its `HTMLInputElement`. The control always uses `type="file"`, accepts one file, and resets its value after every selection. `children`, `dangerouslySetInnerHTML`, `type`, `multiple`, `value`, `defaultValue`, and `hidden` cannot be customized.

Native `required` validation still sees an empty input after selection because the input resets. Validate completed uploads in your application.

`onChange` receives the native change event while the input still contains the selected file. The input then resets before `onFileSelect` fires. Native event props follow React's input contract. `onAbort` is the upload abort action.

## Uploading and disabled states

`isUploading` marks the root busy and makes selection and removal unavailable. Controls that were available stay focusable, so keyboard focus is not lost when an upload starts. Supply `onAbort` to replace Upload with Abort during an upload. Abort works before the first image URL exists. The application owns cancellation and sets `isUploading` back to `false` when the upload ends.

`disabled` disables every action. Selection requires `onFileSelect`. Removal requires both `onRemove` and a nonempty `src`.

<StoryEmbed storyId="ui-input-imageinput--uploading" title="Image upload with an abort action" height={140} />

## Labels, instructions, and errors

Supply localized `uploadLabel`, `removeLabel`, and `abortLabel` strings. They default to `Upload`, `Remove`, and `Abort`. The upload label also names the preview button and the hidden file input. Native accessible attributes can provide a different file input name. `aria-describedby` also describes the selection buttons and combines with the application's helper and error text.

`helperText` and `errorMessage` belong to the application. Both describe the selection controls, and errors are announced as alerts. There are no built-in file limits or product instructions.

<StoryEmbed storyId="ui-input-imageinput--with-error" title="Image input with instructions and an error" height={160} />

## Migration

Replace `onUpload` with `onFileSelect`. Keep `accept` as a top-level prop. The callback still receives a `File`; keep existing validation and upload code in your application.

```tsx theme={null}
import { ImageInput } from 'twenty-ui/components/input';

export const WorkspaceImageSelector = ({
  uploadImage,
}: {
  uploadImage: (file: File) => void;
}) => <ImageInput onFileSelect={uploadImage} accept="image/png, image/jpeg" />;
```

## Props

<ParamField body="abortLabel" type="string" default="Abort">
  Label for the Abort action.
</ParamField>

<ParamField body="accept" type="string" default="image/*">
  Native file picker filter. Defaults to image/\*. The caller validates allowed formats.
</ParamField>

<ParamField body="aria-describedby" type="string">
  Accessible description references for the hidden file input and selection buttons, combined with helperText and errorMessage.
</ParamField>

<ParamField body="aria-label" type="string">
  Accessible name of the hidden file input. Defaults to uploadLabel.
</ParamField>

<ParamField body="aria-labelledby" type="string">
  Accessible name reference for the hidden file input.
</ParamField>

<ParamField body="capture" type="boolean | &#x22;user&#x22; | &#x22;environment&#x22;">
  Native device capture hint for the file picker.
</ParamField>

<ParamField body="className" type="string">
  Class applied to the root element.
</ParamField>

<ParamField body="dir" type="string">
  Text direction applied to both the root and hidden file input.
</ParamField>

<ParamField body="disabled" type="boolean" default="false">
  Disables file selection, removal, and abort actions.
</ParamField>

<ParamField body="errorMessage" type="string | null">
  Application error, displayed as an alert and associated with the selection controls.
</ParamField>

<ParamField body="form" type="string">
  Native form identifier associated with the hidden file input.
</ParamField>

<ParamField body="helperText" type="string">
  Application instructions, associated with the selection controls.
</ParamField>

<ParamField body="id" type="string">
  Native identifier of the hidden file input.
</ParamField>

<ParamField body="inputRef" type="Ref<HTMLInputElement>">
  Ref to the hidden single-file HTMLInputElement.
</ParamField>

<ParamField body="isUploading" type="boolean" default="false">
  Marks the module busy. Selection and removal controls that would otherwise be enabled stay focusable but unavailable. Shows Abort when onAbort is supplied.
</ParamField>

<ParamField body="name" type="string">
  Native name of the hidden file input.
</ParamField>

<ParamField body="onAbort" type="(() => void)">
  Shows an abort action while uploading. It can cancel the first upload before a src exists.
</ParamField>

<ParamField body="onChange" type="ChangeEventHandler<HTMLInputElement, HTMLInputElement>">
  Native file input change event, fired while the selected file is present and before the input resets. The input does not retain a file for form submission.
</ParamField>

<ParamField body="onFileSelect" type="((file: File) => void)">
  Fires when a file is selected and receives its usable File after the input resets. Empty and canceled selections do not call it. Selection is disabled when omitted. The caller owns validation and uploading.
</ParamField>

<ParamField body="onRemove" type="(() => void)">
  Requests removal of the current image. Removal is disabled without this callback or a nonempty src.
</ParamField>

<ParamField body="ref" type="Ref<HTMLDivElement>">
  Ref to the root div element.
</ParamField>

<ParamField body="removeLabel" type="string" default="Remove">
  Label for the Remove action.
</ParamField>

<ParamField body="render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Custom root element or render function. Supply root native attributes here and keep a non-interactive root.
</ParamField>

<ParamField body="required" type="boolean">
  Native file input requirement. The input resets after selection, so the caller validates completed uploads.
</ParamField>

<ParamField body="src" type="string | null">
  Resolved image URL. Empty or failed images show the image placeholder.
</ParamField>

<ParamField body="style" type="CSSProperties">
  Inline style applied to the root element.
</ParamField>

<ParamField body="title" type="string">
  Native title of the hidden file input.
</ParamField>

<ParamField body="uploadLabel" type="string" default="Upload">
  Label for the preview, Upload action, and hidden file input.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.