---
title: "Image and file options"
description: "Configure image uploads to a server using images_upload_handler or images_upload_url. Handle file uploads with custom logic or a server endpoint."
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/file-image-upload/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/file-image-upload/index.md"
version: "latest"
last_updated: "2026-04-13T23:15:36Z"
tokens: 4077
---
# Image and file options

## Controlling or adjusting allowed image and file formats

### `images_file_types`

This option configures which image file formats are accepted by the editor. Changing this option will adjust the following editor behaviour:

- Which image file formats are allowed to be uploaded in the [Image](../image/) dialog.
- Which image file formats are recognized and placed in an `img` element by the core paste and [PowerPaste](../introduction-to-powerpaste/) `smart_paste` functionality.

**Type:** `String`

**Default value:** `'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'`

**Possible values:** A list of valid web image file extensions. For a list of possible values see: [MDN Web Docs - Image file type and format guide](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types).

#### Example: using `images_file_types`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'image',
  toolbar: 'image',
  images_file_types: 'jpg,svg,webp'
});
```

### `file_picker_types`

This option enables you to specify what types of file pickers you need by a space or comma separated list of type names. There are currently three valid types: `file`, `image` and `media`.

**Type:** `String`

**Possible values:** `'file'`, `'image'`, `'media'`

#### Example: using `file_picker_types`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  file_picker_types: 'file image media'
});
```

### `block_unsupported_drop`

When the `block_unsupported_drop` option is set to `true`, the editor blocks unsupported images and files from being dropped into the editor. If the `block_unsupported_drop` option is set to `false`, dropping an unsupported file into the editor will cause the browser to navigate away from the page containing the editor.

**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

#### Example: using `block_unsupported_drop`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  block_unsupported_drop: false
});
```

## Adding a file browser to image and media dialogs

### `file_picker_callback`

This hook can be used to add custom file picker to those dialogs that have it. Once you define `file_picker_callback`, small browse button will appear along the fields of supported file types (see [file_picker_types](#file_picker_types)). When user clicks the button, TinyMCE will automatically call the callback with three arguments:

- **callback** - a callback to call, once you have hold of the file; it expects new value for the field as the first argument and optionally meta information for other fields in the dialog as the second one
- **value** - current value of the affected field
- **meta** - object containing values of other fields in the specified dialog (notice that `meta.filetype` contains the type of the field)

It should be noted, that we only provide a hook. It is up to you to implement specific functionality.

**Type:** `Function`

> **Note:** The following example demonstrates how you can use `file_picker_callback` API, but doesn’t pick any real files. Check the [Interactive example](#interactive-example) for a more functional example.

#### Example: using `file_picker_callback`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  file_picker_callback: (callback, value, meta) => {
    // Provide file and text for the link dialog
    if (meta.filetype == 'file') {
      callback('mypage.html', { text: 'My text' });
    }

    // Provide image and alt text for the image dialog
    if (meta.filetype == 'image') {
      callback('myimage.jpg', { alt: 'My alt text' });
    }

    // Provide alternative source and posted for the media dialog
    if (meta.filetype == 'media') {
      callback('movie.mp4', { source2: 'alt.ogg', poster: 'image.jpg' });
    }
  }
});
```

#### Interactive example

**Example**

```js
tinymce.init({
  selector: 'textarea#file-picker',
  plugins: 'image code',
  toolbar: 'undo redo | link image | code',
  /* enable title field in the Image dialog*/
  image_title: true,
  /* enable automatic uploads of images represented by blob or data URIs*/
  automatic_uploads: true,
  /*
    URL of our upload handler (for more details check: https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_url)
    images_upload_url: 'postAcceptor.php',
    here we add custom filepicker only to Image dialog
  */
  file_picker_types: 'image',
  /* and here's our custom image picker*/
  file_picker_callback: (cb, value, meta) => {
    const input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');

    input.addEventListener('change', (e) => {
      const file = e.target.files[0];

      const reader = new FileReader();
      reader.addEventListener('load', () => {
        /*
          Note: Now we need to register the blob in TinyMCEs image blob
          registry. In the next release this part hopefully won't be
          necessary, as we are looking to handle it internally.
        */
        const id = 'blobid' + (new Date()).getTime();
        const blobCache =  tinymce.activeEditor.editorUpload.blobCache;
        const base64 = reader.result.split(',')[1];
        const blobInfo = blobCache.create(id, file, base64);
        blobCache.add(blobInfo);

        /* call the callback and populate the Title field with the file name */
        cb(blobInfo.blobUri(), { title: file.name });
      });
      reader.readAsDataURL(file);
    });

    input.click();
  },
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});
```

## Customizing how images and files are handled

### `images_upload_handler`

This option allows you to specify a function that is used to replace TinyMCE’s default JavaScript upload handler function with custom logic.

The upload handler function takes two arguments:

- `blobInfo`
- A `progress` callback that takes a value between 1 and 100.

and returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that will resolve with the uploaded image URL or reject with an error. The error can be either a string or an object containing the following properties:

- `message` - The error message to display in the UI.
- `remove` - A flag to remove the image from the document, defaults to `false` if not set.

When this option is not set, TinyMCE utilizes an `XMLHttpRequest` to upload images one at a time to the server and resolves the `Promise` with the JSON `location` property for the remote image returned by the server.

**Type:** `Function`

#### Example: using `images_upload_handler`

```js
const example_image_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest();
  xhr.withCredentials = false;
  xhr.open('POST', 'postAcceptor.php');

  xhr.upload.onprogress = (e) => {
    progress(e.loaded / e.total * 100);
  };

  xhr.onload = () => {
    if (xhr.status === 403) {
      reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
      return;
    }

    if (xhr.status < 200 || xhr.status >= 300) {
      reject('HTTP Error: ' + xhr.status);
      return;
    }

    const json = JSON.parse(xhr.responseText);

    if (!json || typeof json.location != 'string') {
      reject('Invalid JSON: ' + xhr.responseText);
      return;
    }

    resolve(json.location);
  };

  xhr.onerror = () => {
    reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
  };

  const formData = new FormData();
  formData.append('file', blobInfo.blob(), blobInfo.filename());

  xhr.send(formData);
});

tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  images_upload_handler: example_image_upload_handler
});
```

### `images_upload_url`

This option lets you specify a URL for the server-side upload handler. Upload will get triggered whenever you call `editor.uploadImages()` or - automatically, if `automatic_uploads` option is enabled. Upload handler should return a new location for the uploaded file in the following format:

```json
{ "location": "folder/sub-folder/new-location.png" }
```
Be sure to checkout a demo implementation of the server-side upload handler [here](../php-upload-handler/) (written in PHP).

**Type:** `String`

#### Example: using `images_upload_url`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  images_upload_url: 'postAcceptor.php'
});
```

### `files_upload_handler`

This option specifies a function that handles file uploads in the link dialog’s upload tab. This is similar to [`images_upload_handler`](#images_upload_handler), but is specifically designed for document and file uploads.

The upload handler function takes two arguments:

- `blobInfo` - An object containing information about the file blob to upload
- A `progress` callback that takes a value between 1 and 100

and returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that will resolve with an object containing the uploaded file `url` and `fileName`, or reject with an error. The resolved object must have the following structure:

- `url` - The URL of the uploaded file
- `fileName` - The filename of the uploaded file

The error can be either a string or an object containing the following properties:

- `message` - The error message to display in the UI.
- `remove` - A flag to remove the file from the document, defaults to `false` if not set.

When both `files_upload_handler` and [`documents_file_types`](../link/#documents_file_types) are configured, the link dialog displays an "Upload" tab that enables file uploads via the function defined by `files_upload_handler`.

**Type:** `Function`

**Default value:** `undefined`

#### Example: using `files_upload_handler`

This example shows a client-side JavaScript handler that uploads files to a server endpoint. The server should return a JSON response with a `location` property containing the URL of the uploaded file.

```js
const files_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest();
  xhr.withCredentials = false;
  xhr.open('POST', 'upload-handler.php');

  xhr.upload.onprogress = (e) => {
    progress(e.loaded / e.total * 100);
  };

  xhr.onload = () => {
    if (xhr.status === 403) {
      reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
      return;
    }

    if (xhr.status < 200 || xhr.status >= 300) {
      reject('HTTP Error: ' + xhr.status);
      return;
    }

    const json = JSON.parse(xhr.responseText);

    if (!json || typeof json.location != 'string') {
      reject('Invalid JSON: ' + xhr.responseText);
      return;
    }

    resolve({
      url: json.location,
      fileName: blobInfo.filename()
    });
  };

  xhr.onerror = () => {
    reject('File upload failed due to a XHR Transport error. Code: ' + xhr.status);
  };

  const formData = new FormData();
  formData.append('file', blobInfo.blob(), blobInfo.filename());

  xhr.send(formData);
});

tinymce.init({
  selector: 'textarea',
  plugins: 'link',
  toolbar: 'link',
  files_upload_handler: files_upload_handler,
  documents_file_types: [
    { mimeType: 'application/pdf', extensions: [ 'pdf' ] },
    { mimeType: 'application/msword', extensions: [ 'doc' ] },
    { mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extensions: [ 'docx' ] },
    { mimeType: 'text/plain', extensions: [ 'txt' ] }
  ]
});
```

> **Note:** **Server-Side Handler Requirements**
> 
> The server endpoint (e.g., `upload-handler.php` in the example above) should:
> 
> - Accept a POST request with a file in the request body (sent as FormData with the field name `file`)
> - Return a JSON response with a `location` property containing the URL of the uploaded file: `{ "location": "<path-to-your-web-server>/uploaded/file.pdf" }`
> - Handle errors by returning appropriate HTTP status codes (e.g., 403 for forbidden file types, 400 for invalid requests, 500 for server errors)
> - Set appropriate CORS headers if needed for cross-origin requests
> This is similar to how [`images_upload_url`](#images_upload_url) works, but `files_upload_handler` gives you full control over the client-side upload logic, including custom error handling, progress tracking, and request customization.

### `documents_file_types`

This option specifies which file types (MIME types and extensions) are supported for file uploads in the link dialog. When both the [Link](../link/) plugin and the [`files_upload_handler`](../link/#files_upload_handler) are configured, the link dialog displays an "Upload" tab that enables file uploads.

The option should be an array of objects, where each object contains:

- `mimeType` - A string representing the MIME type (e.g., `'application/pdf'`)
- `extensions` - An array of strings representing the file extensions (e.g., `['pdf']`)

**Type:** `Array`

**Default value:** `undefined`

> **Note:** **Priority Behavior**
> 
> When `documents_file_types` is set, it acts as the source of truth for supported file types throughout the editor. This means:
> 
> - The Link plugin uses this custom list instead of its default supported file types
> If `documents_file_types` is not set:
> 
> - The Link plugin uses its default list of supported file types

#### Example: using `documents_file_types`

```js
tinymce.init({
  selector: 'textarea',
  plugins: 'link',
  toolbar: 'link',
  // Configure the file upload handler to handle the file uploads
  files_upload_handler: async (blobInfo, progress) => {
    return { url: 'https://example.com/file.pdf', fileName: 'file.pdf' };
  },
  // Configure the list of supported file types
  documents_file_types: [
    { mimeType: 'application/msword', extensions: [ 'doc' ] },
    { mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extensions: [ 'docx' ] },
    { mimeType: 'application/pdf', extensions: [ 'pdf' ] },
    { mimeType: 'text/plain', extensions: [ 'txt' ] }
  ]
});
```

## Options for improving custom file handling

### `automatic_uploads`

Enable or disable automatic upload of images represented by data URLs or blob URIs. Such images get generated, for example, as a result of image manipulation through the [Image Editing](../editimage/) plugin, or after image is drag-n-dropped onto the editor from the desktop.

> **Note:** This option will do nothing if `images_upload_url` or `images_upload_handler` is not specified.
**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

#### Example: using `automatic_uploads`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  images_upload_url: 'postAcceptor.php',
  automatic_uploads: false
});
```

### `images_upload_base_path`

This option lets you specify a `basepath` to prepend to URLs returned from the configured [`images_upload_url`](#images_upload_url) page.

**Type:** `String`

#### Example: using `images_upload_base_path`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  images_upload_url: 'postAcceptor.php',
  images_upload_base_path: '/some/basepath'
});
```

### `images_upload_credentials`

The **images_upload_credentials** option specifies whether calls to the configured [`images_upload_url`](#images_upload_url) should pass along credentials (such as cookies, authorization headers, or TLS client certificates) for cross-domain uploads. When set to `true`, credentials will be sent to the upload handler, similar to the [`withCredentials` property of `XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials).

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

#### Example: using `images_upload_credentials`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  images_upload_url: 'postAcceptor.php',
  images_upload_credentials: true
});
```

### `images_reuse_filename`

By default TinyMCE will generate unique filename for each uploaded file (for details refer to [Upload Images](../upload-images/#image-uploader-requirements)). Sometimes this might have undesirable side-effects. For example, when `automatic_uploads` is enabled, every manipulation on the image done with the [Image Editing](../editimage/) plugin, results in file upload and each time under a different filename, despite the fact that the image stays the same.

Setting `images_reuse_filename` to *true* tells TinyMCE to use the actual filename of the image, instead of generating a new one each time. Take into account that `src` attribute of the corresponding `<img>` tag gets replaced with whatever filename you send back from the server (see [images_upload_url](#images_upload_url)). It can be the same filename or something else, but the next time that filename is used for the upload.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

#### Example: using `images_reuse_filename`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  automatic_uploads: true,
  images_upload_url: 'postAcceptor.php',
  images_reuse_filename: true
});
```
