<SYSTEM>This is the developer documentation for Mux Uploader for Web, iOS, and Android.</SYSTEM>

# Mux Uploader for web
Mux Uploader is a drop in component for uploading videos to Mux from your web application
**Mux Uploader** is a drop-in web component that makes it easy to upload video files to Mux.

This component allows you to build a fully-functional, customizable video upload UI in your application using a single line of code. Mux Uploader supports:

* Manual file selection
* Drag and drop for files
* Optional pausing and resuming of uploads
* Automatic offline/online detection with upload resumes
* And more!

<Player playbackId={"XYND6DHqq7A01ziIbLWuPH02d004GoqYhHgBucY3M6Tydo"} muted autoPlay loop style={{'--controls': 'none' }} thumbnailTime={0} />

Mux Uploader can be used as either a web component (`<mux-uploader>` from `@mux/mux-uploader`), or a React component (`<MuxUploader />` from `@mux/mux-uploader-react`).

## Quick start

Here are some examples of Mux Uploader in action.

### Mux Uploader HTML element

Install with either npm, yarn or load Mux Uploader from the hosted script.

#### NPM

```shell
npm install @mux/mux-uploader@latest
```

#### Yarn

```shell
yarn add @mux/mux-uploader@latest
```

#### Hosted

```html
<script src="https://cdn.jsdelivr.net/npm/@mux/mux-uploader"></script>
```

#### Example HTML element implementation

```html
<script
  src="https://cdn.jsdelivr.net/npm/@mux/mux-uploader"
></script>
<mux-uploader></mux-uploader>
```

### Mux Uploader React component

You will need to select one of the package options below. Both examples will automatically update the uploader. You can always anchor the package to a specific version if needed.

#### NPM

```shell
npm install @mux/mux-uploader-react@latest
```

#### Yarn

```shell
yarn add @mux/mux-uploader-react@latest
```

#### Example React Usage

```jsx
import MuxUploader from "@mux/mux-uploader-react";

export default function App() {
  return (
    <MuxUploader/>
  );
}
```

## Upload a video

Mux Uploader allows you to use upload URLs provided by Mux's <ApiRefLink href="/docs/api-reference/video/direct-uploads">Direct Uploads</ApiRefLink> in your web application.
It takes care of rendering a file selector, uploading your video file, displaying progress updates to the user, handling retries, and more.

This does mean that you'll need to provide a new upload URL whenever a user will be uploading a new video file in your application. You provide that URL value via the `endpoint` attribute or property. It looks like this:

### HTML example

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<!-- Replace endpoint value with a valid Mux Video Direct Upload URL -->\n<mux-uploader\n  endpoint=\"https://httpbin.org/put\"\n></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js'",
      "hidden": true
    }
  }
}
```

The `endpoint` indicates the direct upload URL that will receive the video file you're uploading.

You can generate a signed direct upload URL by making a server-side API call to Mux's <ApiRefLink href="/docs/api-reference/video/direct-uploads/create-direct-upload">Create Direct Upload</ApiRefLink> endpoint,
or you can use `curl` based on the example from the link if you just want to test it out.

In a successful API response, you will receive a unique signed upload URL that can then be passed along to your client application and set as the `endpoint` property on a `mux-uploader` element. The URL for a Direct Upload looks like `"https://storage.googleapis.com/video..."`.

<Callout type="info">
  In the following examples, you will replace the value of the `endpoint` property with your unique direct upload URL.
</Callout>

### React example

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader from \"@mux/mux-uploader-react\";\n\nexport default function App() {\n  return (\n    <MuxUploader endpoint=\"https://httpbin.org/put\" />\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "template": "react"
}
```

## Overview of the upload process

Video uploads and processing take time. Processing time can vary depending on the file size and type of video that you upload.

Mux uses [webhooks ](/docs/core/listen-for-webhooks)to keep your application informed about what's happening with your uploaded video — from when the upload completes to when the video is ready to be played.

<Callout type="info">
  To minimize processing time, consider following [Mux's guide for handling standard video input](/docs/guides/minimize-processing-time).
</Callout>

The overall flow generally looks like this:

### 1. Set up webhooks

* Set up a public webhook endpoint in your application to receive events from Mux
* Configure the webhook in your Mux dashboard to send events to this endpoint

### 2. Upload the video

* Create a direct upload URL using the Mux API
* Save the upload ID to your database
* Pass the URL to the `endpoint` property on the Mux Uploader component

### 3. Wait for video to be ready

* When the upload completes, show a "processing" indicator to the user.
* Poll your database to check if the video is ready for playback.

### 4. Handle webhook events

Listen for specific webhook events, particularly:

* `video.upload.asset_created` which indicates that the upload has completed and an asset has been created
* `video.asset.ready` which indicates that the video has been processed and is ready for playback

The `video.upload.asset_created` event contains the `asset_id` in the event payload.
The `video.asset.ready` event contains the `playback_id` in the event payload.

### 5. Store the information in your database

Save the `asset_id` and `playback_id` to your database, associating them with the user or relevant entity in your application.

Here's an example of how you might structure your database table schema:

| videos                    |                        |            |
|--------------------------|------------------------|------------|
| id                       | uuid (primary key)     |            |
| user\_id                  | uuid (foreign key)     | References users.id |
| upload\_id                | string                 | From initial upload |
| asset\_id                 | string                 | From Mux webhook |
| playback\_id              | string                 | From Mux webhook |
| title                    | string                 | Optional metadata |
| status                   | enum                   | e.g. `preparing`, `ready` |
| created\_at               | timestamp              |            |
| updated\_at               | timestamp              |            |

### 6. Use the IDs

While Mux generates several IDs during the upload and processing flow, there are two key IDs you'll primarily work with:

1. The `asset_id`: This is used when you need to manage your video through the Mux API (like deleting the video or checking its status)
2. The `playback_id`: This is what you'll use to actually play your video, either by:
   * Adding it to Mux Player
   * Creating a URL where your video can be played

<Callout type="info">
  Note that this process happens asynchronously, so your application should be designed to handle the delay between the initial upload and when the video becomes available for playback.
</Callout>

For more detailed implementations, you can refer to the examples provided in the Mux documentation for various frameworks:

* [Next.js](/docs/frameworks/next-js)
* [SvelteKit](/docs/frameworks/sveltekit)
* [Astro](/docs/frameworks/astro)
* [Remix](/docs/frameworks/remix-js)

## Fetching the upload URL async

At the time you render the `<mux-uploader>`, you may not have the direct upload URL yet. Instead, you might want to retrieve it async from your server after a user selects a file. You can do that by setting the `endpoint` property value to a custom function instead of a URL.

```html
<mux-uploader></mux-uploader>

<script>
  const muxUploader = document.querySelector("mux-uploader");
  /*
    Endpoint should be a function that returns a promise and resolves
    with a string for the upload URL.
  */
  muxUploader.endpoint = function () {
    /*
      In this example, your server endpoint would return the upload URL
      in the response body "https://storage.googleapis.com/video..."
    */
    return fetch("/your-server/api/create-upload").then(res => res.text());
  };
</script>
```

This is even easier using React props:

```jsx
import MuxUploader from "@mux/mux-uploader-react";

export default function App() {
  return (
    <MuxUploader
      endpoint={() => {
        return fetch("/your-server/api/create-upload")
          .then(res => res.text());
      }}
    />
  );
}
```

## Customizing the UI

As you can see in the examples above, Mux Uploader provides a fairly feature rich and reasonably styled (albeit basic) UI by default.

It will automatically update based on different stages or states of uploading, like showing a UI for file selection before a video has been picked,
showing progress as the file is uploaded, showing when the file upload has completed, and showing error state with the option to retry if something
goes wrong with the upload.

In addition, Mux Uploader provides many ways to customize this look and feel, including:

* attributes / properties like `no-drop` or `pausable` to enable/disable UI components
* intuitive styling with CSS, just like any other HTML element.
* state transition attributes like `upload-in-progress` or `upload-error` for responsive styling
* attribute / property based data customization for things like `dynamic-chunk-size` or `max-file-size`
* overridable and composable components like `<mux-uploader-file-select>` or `<mux-uploader-drop>` for full flexibility of UI

<GuideCard
  title="Core functionality"
  description="Understand the features and core functionality of Mux Uploader"
  links={[
    {
      title: "Read the guide",
      href: "/docs/guides/uploader-web-core-functionality",
    },
  ]}
/>

<GuideCard
  title="Integrate Mux Uploader"
  description="Interate Mux Uploader in your web application. See examples in popular front end frameworks."
  links={[
    {
      title: "Read the guide",
      href: "/docs/guides/uploader-web-integrate-in-your-webapp",
    },
  ]}
/>

<GuideCard
  title="Customize the look and feel"
  description="Customize Mux Uploader to match your brand and needs"
  links={[
    {
      title: "Read the guide",
      href: "/docs/guides/uploader-web-customize-look-and-feel",
    },
  ]}
/>


# Core functionality of Mux Uploader
In this guide, see the features and functionality that Mux Uploader gives you out of the box.
## Mux Video integration

Mux Uploader is built for working with Mux's [Direct Uploads](/docs/guides/upload-files-directly) API and workflow. Add your upload
URL as Mux Uploader's [`endpoint`](/docs/guides/mux-uploader#upload-a-video) to use it.

Mux Uploader uses [UpChunk](https://github.com/muxinc/upchunk) under the hood to handle large files by splitting them into small chunks before uploading them.

## Controls and UI

Mux Uploader provides a feature-rich, dynamic UI that changes based on the current state of your media upload.
These can be broken down into:

| State | Attribute | Description |
| ----- | --------- | ----------- |
| Initial | (none) | State before a media file has been selected for upload |
| In Progress | `upload-in-progress` | State while media chunks are being uploaded |
| Completed | `upload-complete` | State after the media has successfully finished uploading all chunks |
| Error | `upload-error` | State whenever an error occurs that results in a failure to fully upload the media |

## Initial State

The initial state by default will show both a drag and drop region and a file select button to select your file for upload.
By default, it looks like this:

<Image src="/docs/images/mux-uploader-web-drop.png" width={502} height={210} />

## In Progress State

Under normal conditions, the in progress state will indicate the ongoing uploading progress as both a numeric percentage and
a progress bar. It will look something like this:

<Image src="/docs/images/mux-uploader-web-progress.png" width={435} height={129} />

### Pausing

In addition, you can [opt into pausing](/docs/guides/uploader-web-customize-look-and-feel#enable-pausing), in which case the UI
will look like one of these, depending on if you are unpaused, pausing (after the current chunk finishes uploading), or paused.

<MultiImage
  images={[
  { src: "/docs/images/mux-uploader-web-pause.png", width: 710, height: 173 },
  { src: "/docs/images/mux-uploader-web-pausing.png", width: 710, height: 173 },
  { src: "/docs/images/mux-uploader-web-resume.png", width: 710, height: 173 },
]}
/>

### Offline

Finally, if you unfortunately end up loosing internet connection while uploading is in progress, you'll see this:

<Image src="/docs/images/mux-uploader-web-offline.png" width={436} height={182} />

## Completed State

Once uploading has completed, Mux Uploader will present the following status:

<Image src="/docs/images/mux-uploader-web-complete.png" width={436} height={108} />

## Error State

And in the unfortunate case where you encounter an error, by default you'll see the error message and a retry button:

<Image src="/docs/images/mux-uploader-web-retry.png" width={710} height={160} />

<Callout type="info">
  If you want to explore different ways to customize the UI for these different states,
  check out our documentation on [customizing Mux Uploader's look and feel](/docs/guides/uploader-web-customize-look-and-feel).
</Callout>

## Error handling

Mux Uploader will monitor for unrecoverable errors and surface them via the UI, giving the
user the opportunity to retry the upload. Mux Uploader monitors both HTTP-status based errors
(e.g. 4xx, 5xx statuses) and file processing errors like exceeding maximum file size limits. See our [optional configuration options](#configure-upload-details) below for more ways to work around some of these errors.

In addition, before surfacing an HTTP-based error, Mux Uploader will automatically retry the request 5 times.

You may also listen for these errors via the `uploaderror` event, discussed in the section below.

## Using events

All of Mux Uploader's core UI behaviors and functionality are driven by specific events. These fall into two
categories:

1. user-driven update events (e.g. notifying Mux Uploader which file to upload or to retry uploading after an error)
2. state-driven informational events (e.g. notifying subcomponents or anyone else listening about the upload progress or that an error occurred)

For example, you can listen for the `progress` event to receive details on how far along your file upload is.

```js
  const muxUploader = document.querySelector('mux-uploader');

  muxUploader.addEventListener('progress', function (e) {
    console.log(`My upload is ${e.detail}% complete!`)
  });
```

When the upload is complete, you'll see 100% on the progress bar and the `success` event will fire.

If an error occurs during the upload, an `uploaderror` event will fire.

### Example HTML Usage

```html
<mux-uploader endpoint="https://my-authenticated-url/storage?your-url-params"></mux-uploader>

<script>
  const muxUploader = document.querySelector('mux-uploader');

  muxUploader.addEventListener('success', function () {
    // Handle upload success
  });

  muxUploader.addEventListener('uploaderror', function () {
    // Handle upload error
  });
</script>
```

### Example React Usage

```jsx
import MuxUploader from "@mux/mux-uploader-react";

export default function App() {
  return (
    <MuxUploader
      endpoint="https://my-authenticated-url/storage?your-url-params"
      onSuccess={() => {
        // Handle upload success
      }}
      onUploadError={() => {
        // Handle upload error
      }}
    />
  );
}
```

## Configure Upload Details

In addition to various UI customization and behaviors, Mux Uploader exposes the following attributes / properties for configuring details
about the file upload itself:

| Attribute / Property | Description |
| --- | --- |
| `max-file-size` / `maxFileSize` | The largest size, in kB, allowed for upload |
| `chunk-size` / `chunkSize` | The size of each upload chunk, in kB. Useful for advanced optimization based on known network conditions or file details. |
| `dynamic-chunk-size` / `dynamicChunkSize` | A boolean that tells Mux Uploader to automatically adapt its chunk size larger or smaller based on network conditions. |
| `use-large-file-workaround` / `useLargeFileWorkaround` | A boolean that enables a less memory efficient way of loading and chunking files for environments that don't reliably handle [`ReadableStream` for large files](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams). This can occur on e.g. Safari browsers with files >= 4GB. **NOTE:** This fallback will only be used if and when attempts to use `ReadableStream` fails. |

## Full API reference

Any features or settings not mentioned above can be found in our [full API reference](https://github.com/muxinc/elements/blob/main/packages/mux-uploader/REFERENCE.md)
covering all of the available events, attributes, properties, slots, CSS parts, and CSS variables available on Mux Uploader and all of its subcomponents.


# Integrate Mux Uploader into your web application
In this guide, you will learn about Mux Uploader and how to use it in your web application.
## Install Mux Uploader

Mux Uploader has 2 packages:

* `@mux/mux-uploader`: the web component, compatible with all frontend frameworks
* `@mux/mux-uploader-react`: the React component, for usage in React

Both are built with TypeScript and can be installed either via `npm`, `yarn` or the hosted option on `jsdelivr`.

### NPM

```shell
npm install @mux/mux-uploader@latest #or @mux/mux-uploader-react@latest
```

### Yarn

```shell
yarn add @mux/mux-uploader@latest #or @mux/mux-uploader-react@latest
```

### Hosted

```html
<script src="https://cdn.jsdelivr.net/npm/@mux/mux-uploader"></script>
<!--
or src="https://cdn.jsdelivr.net/npm/@mux/mux-uploader-react"
-->
```

## Providing attributes

The only required value to use Mux uploader is [`endpoint`](/docs/guides/mux-uploader#upload-a-video).

## Examples

### HTML element

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<!-- Replace endpoint value with a valid Mux Video Direct Upload URL -->\n<mux-uploader\n  endpoint=\"https://httpbin.org/put\"\n></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js'",
      "hidden": true
    }
  }
}
```

Using in HTML just requires adding the hosted `<script>` tag to your page and then adding the `<mux-uploader>` element where you need it.

### React

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader from \"@mux/mux-uploader-react\";\n\nexport default function App() {\n  return (\n    <MuxUploader endpoint=\"https://httpbin.org/put\" />\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "template": "react"
}
```

For our React implementation, you can use it just like you would any other React component.

### Svelte

Because Svelte supports web components, it doesn't need a separate wrapper component like React. View the SveltKit example in the
[Mux Elements repo](https://github.com/muxinc/elements/tree/main/examples/svelte-kit) for a fully functioning example.

```html
<script context="module" lang="ts">
  export const prerender = true;
</script>

<script lang="ts">
  // this prevents the custom elements from being redefined when the REPL is updated and reloads, which throws an error
  // this means that any changes to the custom element won't be picked up without saving and refreshing the REPL
  // const oldRegister = customElements.define;
  // customElements.define = function(name, constructor, options) {
  // 	if (!customElements.get(name)) {
  // 		oldRegister(name, constructor, options);
  // 	}
  // }
  // import { page } from '$app/stores';
  import { onMount } from "svelte";
  onMount(async () => {
    await import("@mux/mux-uploader");
  });
</script>

<mux-uploader endpoint="https://httpbin.org/put" />
```

### Vue

Because Vue supports web components, it doesn't need a separate wrapper component like React. View the Vue example in the [Mux Elements repo](https://github.com/muxinc/elements/tree/main/examples/vue-with-typescript) for a fully functioning example.

```html
<script setup lang="ts">
  import "@mux/mux-uploader";
</script>

<template>
  <main>
    <mux-uploader endpoint="https://httpbin.org/put" />
  </main>
</template>
```

<GuideCard
  title="Customize the look and feel"
  description="Customize Mux Uploader to match your brand"
  links={[
    {
      title: "Read the guide",
      href: "/docs/guides/uploader-web-customize-look-and-feel",
    },
  ]}
/>

{/* <GuideCard
    title="Advanced usage"
    description="Learn about advanced usage of Mux Player"
    links={[
      {
        title: "Read the guide",
        href: "/docs/guides/player-advanced-usage",
      },
    ]}
  /> */}


# Customize the look and feel of Mux Uploader
Learn how to customize the look and feel of Mux Uploader to fit your brand and use case.
## Configure UI features

The basic use case of Mux Uploader includes many UI features which may be enabled or disabled by default.
You can toggle many of these via attributes/properties.

### Enable pausing

For larger video files, you may want to allow your users to pause and resume an upload. You can enable this in the UI using
the `pausable` attribute, property, or React prop.

Because Mux Uploader uploads the file in chunks, it will wait to complete uploading the current chunk before pausing. To indicate this,
the pause button will actually have 3 states:

1. Pause - indicates the upload is not currently paused, but can be by pressing the button.
2. Pausing - indicates that the upload will pause once the current chunk upload finishes. The button will be disabled in this case.
3. Resume - indicates the upload is currently paused, but can be resumed by pressing the button.

Below are examples of what this looks like in the UI.

<MultiImage
  images={[
  { src: "/docs/images/mux-uploader-web-pause.png", width: 710, height: 173 },
  { src: "/docs/images/mux-uploader-web-pausing.png", width: 710, height: 173 },
  { src: "/docs/images/mux-uploader-web-resume.png", width: 710, height: 173 },
]}
/>

### Disable Retrying

If for some reason your video upload fails, Mux Uploader will allow a user to retry via the UI. You can disable this using the
`no-retry` attribute or `noRetry` property in the web component, or just `noRetry` prop in React.

Below are examples of what this looks like in the UI.

<MultiImage
  images={[
  { src: "/docs/images/mux-uploader-web-retry.png", width: 710, height: 160 },
  { src: "/docs/images/mux-uploader-web-no-retry.png", width: 710, height: 141 },
]}
/>

### Disable Drag & Drop

Mux Uploader makes drag and drop available for your video files by default. You can disable this using the
`no-drop` attribute or `noDrop` property in the web component, or just `noDrop` prop in React.

Below are examples of what this looks like in the UI.

<MultiImage
  images={[
  { src: "/docs/images/mux-uploader-web-drop.png", width: 502, height: 210 },
  { src: "/docs/images/mux-uploader-web-no-drop.png", width: 710, height: 50 },
]}
/>

<Callout type="info">
  **Note:** There are two likely cases where you may want to disable drag and drop on Mux Uploader:

  1. You still want to support drag and drop, but your page or application design needs the drop zone component somewhere different.
     Mux Uploader supports this by allowing you to [use its subcomponents directly](/docs/guides/uploader-web-use-subcomponents-directly).
  2. You want to use Mux Uploader with all of its features baked in but drag and drop doesn't make sense for your designs. Because
     things like the upload progress UI requires more space for its display, you'll probably also want to
     [use CSS to customize Mux Uploader](#style-with-css).
</Callout>

### Disable other UI subcomponents or features

Mux Uploader also provides attributes and properties to disable:

* The upload progress UI (`no-progress` / `noProgress` for the web component attribute / property, `noProgress` for the React prop)
* The upload status UI (e.g. when the upload is complete or when an error occurs) (`no-status` / `noStatus` for the web component attribute / property, `noStatus` for the React prop)

Since removing these UI elements might result in a poor user experience, you may want to [use Mux Uploader's subcomponents directly](/docs/guides/uploader-web-use-subcomponents-directly) for a more bespoke design when doing so.

## Override the file selector with slots

Because Mux Uploader is a [web component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components), it lets you provide your
own file select element simply by adding it as a child and using the [named slot](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots#using_the_element-details_custom_element_with_named_slots)
`slot="file-select"` attribute or property.

This is really handy if, for example, you already have a `.btn` class or similar that styles buttons in your application. For example:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  .btn {\n    /* your styles for .btn */\n    padding: 6px 8px;\n    border: 1px solid #0d9488;\n    border-radius: 5px;\n    font-size: 24px;\n    color: white;\n    background: deeppink;\n    cursor: pointer;\n  }\n</style>\n\n<!-- slot=\"file-select\" tells mux-uploader to replace the default file selector with a button.btn element -->\n<mux-uploader endpoint=\"https://httpbin.org/put\">\n  <button class=\"btn\" type=\"button\" slot=\"file-select\">Pick a file</button>\n</mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js'",
      "hidden": true
    }
  }
}
```

The same applies to the React version of the component, `<MuxUploader/>`, as it's just a wrapper around the web component:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader from \"@mux/mux-uploader-react\";\n\nexport default function App() {\n  return (\n    <MuxUploader endpoint=\"https://httpbin.org/put\">\n      <button\n        slot=\"file-select\"\n        type=\"button\"\n        style={{\n          /* your styles for .btn */\n          padding: '6px 8px',\n          border: '1px solid #0d9488',\n          borderRadius: 5,\n          fontSize: 24,\n          color: 'white',\n          background: 'deeppink',\n          cursor: 'pointer',\n        }}\n      >Pick a file</button>\n    </MuxUploader>\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "template": "react"
}
```

## Style with CSS

The Mux Uploader element, `<mux-uploader>`, can be styled and positioned with CSS just like you would any other HTML element. For example:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  mux-uploader {\n    display: inline-flex;\n    width: 350px;\n    height: 275px;\n    color: white;\n    background: hotpink;\n    font-family: \"Gill Sans\", sans-serif;\n  }\n</style>\n\n<!-- slot=\"file-select\" tells mux-uploader to replace the default file selector with a button.btn element -->\n<mux-uploader endpoint=\"https://httpbin.org/put\"></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js'",
      "hidden": true
    }
  }
}
```

Because Mux Uploader React is a wrapper around the HTML element, the same applies to it as well:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader from \"@mux/mux-uploader-react\";\n\nexport default function App() {\n  return (\n    <MuxUploader\n      endpoint=\"https://httpbin.org/put\"\n      style={{\n        display: 'inline-flex',\n        width: 350,\n        height: 275,\n        color: 'white',\n        background: 'hotpink',\n        fontFamily: '\"Gill Sans\", sans-serif',\n      }}\n    />\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "template": "react"
}
```

<Callout type="info" title="A couple of notes here:">
  * Mux Uploader relies on certain styles for its layout, so take care when overriding them. For example: flexbox is used by default to layout
    its subcomponents so it might be best to prefer `display: inline-flex` instead of potentially changing it to `inline` or `inline-block`.
  * Because Mux Uploader is a complex component made up of various sub-components, your mileage may vary on simply relying
    on CSS to style the component. In these more advanced cases of styling, you may want to explore [using CSS variables](#use-css-variables-for-additional-styling) or
    [using the Mux Uploader subcomponents directly](/docs/guides/uploader-web-use-subcomponents-directly).
</Callout>

### Use CSS variables for additional styling

In addition to styling with standard CSS, Mux Uploader exposes some additional styles via [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).
This allows you to tweak some of the "under the hood" subcomponents' styles simply. These include:

| Name                            | CSS Property       | Default Value               | Description                                     |
| ------------------------------- | ------------------ | --------------------------- | ----------------------------------------------- |
| `--overlay-background-color`    | `background-color` | `rgba(226, 253, 255, 0.95)` | background color of the drop overlay            |
| `--progress-bar-fill-color`     | `background`       | `#000000`                   | color for progress bar                          |
| `--progress-percentage-display` | `display`          | `block`                     | display value for text percentage progress UI   |
| `--progress-radial-fill-color`  | `stroke`           | `black`                     | stroke color for radial progress (experimental) |

Building off of the prior examples, you can use these just like you would other CSS variables:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  mux-uploader {\n    --overlay-background-color: purple;\n    --progress-bar-fill-color: purple;\n    --progress-percentage-display: none;\n    display: inline-flex;\n    width: 350px;\n    height: 275px;\n    color: white;\n    background: hotpink;\n    font-family: \"Gill Sans\", sans-serif;\n  }\n</style>\n\n<!-- slot=\"file-select\" tells mux-uploader to replace the default file selector with a button.btn element -->\n<mux-uploader endpoint=\"https://httpbin.org/put\"></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js'",
      "hidden": true
    }
  }
}
```

And for React:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader from \"@mux/mux-uploader-react\";\n\nexport default function App() {\n  return (\n    <MuxUploader\n      endpoint=\"https://httpbin.org/put\"\n      style={{\n        '--overlay-background-color': 'purple',\n        '--progress-bar-fill-color': 'purple',\n        '--progress-percentage-display': 'none',\n        display: 'inline-flex',\n        width: 350,\n        height: 275,\n        color: 'white',\n        background: 'hotpink',\n        fontFamily: '\"Gill Sans\", sans-serif',\n      }}\n    />\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "template": "react"
}
```

### Use uploader attributes for state-driven styling

Mux Uploader uses read-only properties and attributes to manage and advertise different state changes during the upload process.

These are:

| State | Description |
| --- | --- |
| (none) | Upload has not yet begun |
| `upload-in-progress` | Upload is currently in progress. **NOTE:** This includes while the upload is paused. |
| `upload-complete` | Upload has completed. |
| `upload-error` | An error occurred while attempting to upload. |

These allow you to use [attribute selectors](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors)
if you want state-driven, dynamic styling via CSS.

Here's a basic example of these in action that builds off of the prior examples:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  mux-uploader {\n    --overlay-background-color: purple;\n    --progress-bar-fill-color: purple;\n    --progress-percentage-display: none;\n    display: inline-flex;\n    width: 350px;\n    height: 275px;\n    color: white;\n    background: hotpink;\n    font-family: \"Gill Sans\", sans-serif;\n  }\n\n  mux-uploader[upload-in-progress] {\n    background: orange;\n  }\n\n  mux-uploader[upload-complete] {\n    background: green;\n  }\n</style>\n\n<!-- slot=\"file-select\" tells mux-uploader to replace the default file selector with a button.btn element -->\n<mux-uploader endpoint=\"https://httpbin.org/put\"></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js'",
      "hidden": true
    }
  }
}
```

<Callout type="info">
  **NOTE:** Because Mux Uploader React is a thin wrapper around the Mux Uploader web component, you can use these exact same CSS selectors
  in your React application. Alternatively, some frameworks, like [Tailwind CSS](https://tailwindcss.com/), have built-in support for arbitrary
  attribute selectors. For an example of this in use, see the [section below](#using-tailwind-css).
</Callout>

### Styling in React

If you're using React to build your application, there are some common patterns used in React that are less likely to be relevant for
the web component version. Below are a couple of these.

### Using CSS modules

One common pattern for styling in React is to use CSS-in-JS, for example, using CSS modules:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import styles from \"./Styles.module.css\";\nimport MuxUploader from \"@mux/mux-uploader-react\";\n\nexport default function App() {\n  return (\n    <MuxUploader className={styles.uploader} endpoint=\"https://httpbin.org/put\" />\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    },
    "/Styles.module.css": {
      "code": ".uploader {\n  --overlay-background-color: purple;\n  --progress-bar-fill-color: purple;\n  --progress-percentage-display: none;\n  display: inline-flex;\n  width: 350px;\n  height: 275px;\n  color: white;\n  background: hotpink;\n  font-family: \"Gill Sans\", sans-serif;\n}\n"
    }
  },
  "template": "react"
}
```

### Using Tailwind CSS

Another common approach to styling React applications is using [Tailwind CSS](https://tailwindcss.com). Here's an example for Mux Uploader
approximating the previous examples, including CSS variables via
[arbitrary properties](https://tailwindcss.com/docs/adding-custom-styles#arbitrary-properties) and attribute selectors via
[arbitrary variants](https://tailwindcss.com/docs/hover-focus-and-other-states#using-arbitrary-variants):

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader from \"@mux/mux-uploader-react\";\n\n// Declaring the tailwind classes as an array for legibility\nconst stylesList = [\n  'inline-flex',\n  'w-4/5',\n  'h-4/5',\n  'font-sans',\n  'text-white',\n  'bg-pink-400',\n  '[--progress-percentage-display:none]',\n  '[--overlay-background-color:purple]',\n  '[--progress-bar-fill-color:purple]',\n  '[&[upload-in-progress]]:bg-orange-500',\n  '[&[upload-complete]]:bg-green-500',\n];\n\nconst stylesStr = stylesList.join(' ');\n\nexport default function App() {\n  return (\n    <MuxUploader\n      className={stylesStr}\n      endpoint=\"https://httpbin.org/put\"\n    />\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "options": {
    "externalResources": [
      "https://cdn.tailwindcss.com"
    ]
  },
  "template": "react"
}
```


# Compose custom UIs with subcomponents
Learn how to use Mux Uploader's various subcomponents to compose even more bespoke user experiences and designs.
Although Mux Uploader is a single component that's easy to drop into your web application, it's actually built using several subcomponents
"under the hood." If your application design or desired user experience requires more customization, you can use the individual web components that come packaged with Mux Uploader to build out a custom upload UI that meets your needs.

To use this approach, add an `id` attribute to your `<mux-uploader>` element with a unique value.

You can then associate the `<mux-uploader>` element with any of the packaged components by adding a `mux-uploader=""` attribute to each component and setting it to the `id` that you gave to the `<mux-uploader>` element.

Here's a simple example for the web component:

```html
<!-- add a mux-uploader tag with an id attribute and hide it with CSS -->
<mux-uploader id="my-uploader" style="display: none;"></mux-uploader>

<!-- ...then, somewhere else in your app, add a reference back to it -->
<mux-uploader-file-select mux-uploader="my-uploader">
  <button slot="file-select">Pick a video</button>
</mux-uploader-file-select>
```

Here's one for React:

```jsx
import MuxUploader, { MuxUploaderFileSelect } from "@mux/mux-uploader-react";

export default function App() {
  return (
    <MuxUploader id="my-uploader" style={{ display: "none"}} />

    {/* ...then, somewhere else in your app, add a reference back to it */}
    <MuxUploaderFileSelect mux-uploader="my-uploader">
      <button slot="file-select">Pick a video</button>
    </mux-uploader-file-select>
  );
}
```

Because all of these are web components, you can use CSS to style them or
any of their slotted children (discussed below).

# Subcomponents

## File Select

The file select subcomponent is what tells Mux Uploader to open the file selection browser. The web component is
`<mux-uploader-file-select>`, and the React component is `<MuxUploaderFileSelect>`.

You can further customize it by slotting in your own `<button>` or other component in the `file-select` slot.

Here's an example:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  /* Hide the uploader before uploading */\n  mux-uploader:not([upload-error]):not([upload-in-progress]):not([upload-complete]) {\n    display: none;\n  }\n\n  mux-uploader-file-select button {\n    background: hotpink;\n    color: white;\n    padding: 4px 2px;\n    border: none;\n  }\n\n  mux-uploader-file-select button:hover {\n    background: purple;\n  }\n</style>\n<!-- In this example, we're still using Mux Uploader as a visual component -->\n<mux-uploader\n    id=\"my-uploader\"\n    no-drop\n    endpoint=\"https://httpbin.org/put\"\n  ></mux-uploader>\n<mux-uploader-file-select mux-uploader=\"my-uploader\">\n  <button>Select from a folder</button>\n</mux-uploader-file-select>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

## Drop

The drop subcomponent is what implements the [drag and drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API)
and tells Mux Uploader the relevant details about the file.
The web component is `<mux-uploader-drop>`, and the React component is `<MuxUploaderDrop>`.

Mux Uploader Drop provides a few slots for customization.

* `heading` - By default this is a `<span>` with the text "Drop a video file here to upload".
* `separator` - By default this is a `<span>` containing the text "or" placed between the heading and any additional children.
* (default) - Any additional children that don't have a specified slot will show up below the two previous slots.

Here's an example that puts all of these together, including CSS:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  /* Customize drop area background color & active background color */\n  mux-uploader-drop {\n    padding: 40px;\n    color: white;\n    background: hotpink;\n  }\n\n  mux-uploader-drop[active] {\n    background: #ffe4e6;\n  }\n</style>\n\n<mux-uploader-drop mux-uploader=\"my-uploader\">\n  <!-- Change the heading text/UI shown -->\n  <div slot=\"heading\">Drop videoz here plz</div>\n  <!-- Remove/hide the separator text/UI (default \"Or\") -->\n  <div slot=\"separator\" style=\"display: none;\"></div>\n  <div>You can also add arbitrary children for designs like the drop zone being the full screen</div>\n</mux-uploader-drop>\n<!-- In this example, we're still using Mux Uploader as a visual component -->\n<mux-uploader\n    id=\"my-uploader\"\n    no-drop\n    endpoint=\"https://httpbin.org/put\"\n  ></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

In addition, Mux Uploader Drop has attributes/properties for optionally showing an overlay whenever a file is
dragged over it. These are on by default in Mux Uploader, and are:

* `overlay` - A boolean attribute / property / React prop for enabling the overlay UI.
* `overlay-text` (`overlayText` property and React prop) - Allows you to provide custom text to show on the overlay.

If you'd like to further customize the overlay with a different background color, you can use the
`--overlay-background-color` CSS variable (which is also available when [using Mux Uploader directly](/docs/guides/uploader-web-customize-look-and-feel#use-css-variables-for-additional-styling))

Here's an example of these in action:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  /* Customize drop area background color & overlay background color */\n  mux-uploader-drop {\n    padding: 40px;\n    color: white;\n    background: hotpink;\n    --overlay-background-color: purple;\n  }\n</style>\n\n<!-- Use an overlay with customized overlay text -->\n<mux-uploader-drop overlay-text=\"Just let go!\" overlay mux-uploader=\"my-uploader\">\n  <!-- Change the heading text/UI shown -->\n  <div slot=\"heading\">Drop videoz here plz</div>\n  <!-- Remove/hide the separator text/UI (default \"Or\") -->\n  <div slot=\"separator\" style=\"display: none;\"></div>\n  <div>You can also add arbitrary children for designs like the drop zone being the full screen</div>\n</mux-uploader-drop>\n<!-- In this example, we're still using Mux Uploader as a visual component -->\n<mux-uploader\n    id=\"my-uploader\"\n    no-drop\n    endpoint=\"https://httpbin.org/put\"\n  ></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

### Custom Drop

You can even implement your own drag and drop completely separate from `<mux-uploader>` and as long as you dispatch a custom `file-ready` with the file in the `detail` property then `<mux-uploader>` will handle the upload upon receiving the event.

```html
<script>
  const muxUploader = document.querySelector("mux-uploader");

  // Dispatch custom event to trigger upload
  muxUploader.dispatchEvent(
    new CustomEvent("file-ready", {
      composed: true,
      bubbles: true,
      detail: file,
    })
  );
</script>
```

## Progress

The progress subcomponent is what visualizes progress of your upload. In fact, it is used twice "under the hood" by the default `<mux-uploader>`:
once for showing the %, and once for showing the progress bar.
The web component is `<mux-uploader-progress>`, and the React component is `<MuxUploaderProgress>`.

In addition, Mux Uploader Progress exposes the `type` attribute / property / React prop for choosing the particular kind of visualization you'd prefer. The
available type values are:

* `percentage` (default) - Show as a numeric % in text
* `bar` - Show as a progress bar
* `radial` (***Experimental***) - Show as a radial/circular progress indicator

Each of these types also has CSS variables available for further customization:

`percentage`:

* `--progress-percentage-display` - Applies to the `display` of the underlying percentage element (default: `block`).

`bar`:

* `--progress-bar-height` - Applies to the `height` of the progress bar (default: `4px`).
* `--progress-bar-fill-color` - Applies to the color of the progress bar's progress indication (default: `black`).

`radial`:

* `--progress-radial-fill-color` - Applies to the color of the radial progress indication (default: `black`).

Here's an example of these in action:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  mux-uploader-progress {\n    --progress-bar-fill-color: purple;\n    --progress-radial-fill-color: purple;\n    color: purple;\n    --progress-bar-height: 10px;\n  }\n</style>\n<!-- In this example, we're still using Mux Uploader as a visual component -->\n<mux-uploader\n    id=\"my-uploader\"\n    no-progress\n    no-drop\n    endpoint=\"https://httpbin.org/put\"\n  ></mux-uploader>\n  <mux-uploader-progress\n  type=\"percentage\"\n  mux-uploader=\"my-uploader\"\n></mux-uploader-progress>\n<mux-uploader-progress\n  type=\"bar\"\n  mux-uploader=\"my-uploader\"\n></mux-uploader-progress>\n<mux-uploader-progress\n  type=\"radial\"\n  mux-uploader=\"my-uploader\"\n></mux-uploader-progress>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

## Status

The status subcomponent is what indicates when the upload is completed, or an error has occurred, or when you're offline.
The web component is `<mux-uploader-status>`, and the React component is `<MuxUploaderStatus>`.

Here's an example with a bit of CSS customization, using Mux Uploader's [state attributes](/docs/guides/uploader-web-customize-look-and-feel#use-uploader-attributes-for-state-driven-styling)
on the status component for additional state-driven styling:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  mux-uploader {\n    height: 2rem;\n    padding: 4px 2px;\n  }\n\n  mux-uploader-status {\n    background: hotpink;\n    color: white;\n    padding: 4px 2px;\n    height: 2rem;\n    display: block;\n  }\n\n  mux-uploader-status[upload-error] {\n    background: crimson;\n    /* By default, the error text color will be red. */\n    color: white;\n  }\n\n  mux-uploader-status[upload-complete] {\n    background: dodgerblue;\n  }\n\n  mux-uploader-file-select button:hover {\n    background: purple;\n  }\n</style>\n<mux-uploader-status mux-uploader=\"my-uploader\"></mux-uploader-status>\n<!--\n  In this example, we're still using Mux Uploader as a visual component.\n  Change the endpoint to an invalid one to see what an error looks like.\n-->\n<mux-uploader\n    id=\"my-uploader\"\n    no-drop\n    no-status\n    endpoint=\"https://httpbin.org/put\"\n  ></mux-uploader>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

## Retry

The retry subcomponent that is displayed when an error has occurred to retry uploading and will notify Mux Uploader to retry when clicked.
The web component is `<mux-uploader-retry>`, and the React component is `<MuxUploaderRetry>`.

Here's a simple example:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<!-- In this example, we're still using Mux Uploader as a visual component. -->\n<mux-uploader\n    id=\"my-uploader\"\n    no-drop\n    no-retry\n    endpoint=\"http://fake.url.for/retry/purposes\"\n  ></mux-uploader>\n<mux-uploader-retry mux-uploader=\"my-uploader\"></mux-uploader-retry>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

## Pause

The pause subcomponent that is displayed while an upload is in progress and will notify Mux Uploader to either pause or resume uploading
when clicked, depending on the current uploading state.
The web component is `<mux-uploader-pause>`, and the React component is `<MuxUploaderPause>`.

Here's a simple example:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<!--\n  In this example, we're still using Mux Uploader as a visual component.\n  We've also made the chunk size smaller to help demo pause/resume behavior.\n-->\n<mux-uploader\n  id=\"my-uploader\"\n  no-drop\n  chunk-size=\"512\"\n  endpoint=\"https://httpbin.org/put\"\n></mux-uploader>\n<mux-uploader-pause mux-uploader=\"my-uploader\"></mux-uploader-pause>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```

# Advanced use cases

Here are some more examples of working with the subcomponents directly, using multiple subcomponents together to demonstrate the versatility
and composability of using the various subcomponents together in either React or vanilla HTML.

## React CSS modules

Just like you can do with the "batteries" usage of Mux Uploader, you can use [CSS-in-JS](/docs/guides/uploader-web-customize-look-and-feel#using-css-modules)
to handle styling of your subcomponents in React. Here's an example of how you can style Mux Uploader using CSS modules:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import styles from \"./Styles.module.css\";\nimport MuxUploader, { MuxUploaderFileSelect, MuxUploaderProgress } from \"@mux/mux-uploader-react\"; \n\nexport default function App() {\n  return (\n    <div>\n        <h2 className={styles.heading}>Mux Uploader with CSS Modules</h2>\n        <MuxUploader id=\"css-modules-uploader\" className={styles.uploader} endpoint=\"https://httpbin.org/put\" />\n        <MuxUploaderFileSelect muxUploader=\"css-modules-uploader\">\n          <button className={styles.button}>Pick your video</button>\n        </MuxUploaderFileSelect>\n        <MuxUploaderProgress type=\"percentage\" muxUploader=\"css-modules-uploader\" className={styles.progress} />\n    </div>\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    },
    "/Styles.module.css": {
      "code": ".heading {color: #333;}\n.uploader { display: none; }\n.progress { color: orange; }\n.button {\n    background: #3a3a9d;\n    padding: 1em;\n    color: white;\n    border-radius: .35em;\n    border: 0;\n    cursor: pointer;\n}\n    "
    }
  },
  "template": "react"
}
```

## React Tailwind CSS

Also like Mux Uploader, you can use [Tailwind CSS](/docs/guides/uploader-web-customize-look-and-feel#using-tailwind-css) for your subcomponent styling. Here's an example in React:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader-react": "latest"
    }
  },
  "files": {
    "/App.js": {
      "code": "import MuxUploader, { MuxUploaderFileSelect, MuxUploaderProgress, MuxUploaderDrop } from \"@mux/mux-uploader-react\"; \n\nexport default function App() {\n  return (\n    <div className=\"p-4\">\n        <h2 className=\"text-lg text-slate-800 mb-2 font-bold\">Mux Uploader with Tailwind example</h2>\n        <MuxUploader id=\"my-uploader\" className=\"hidden\" endpoint=\"https://httpbin.org/put\" />\n\n        <MuxUploaderDrop\n            id=\"my-uploader\"\n            className=\"border border-4 border-slate-200 rounded-0.125 shadow mb-4\"\n            overlay\n            overlayText=\"Let it go\"\n        >\n            <span slot=\"heading\" className=\"text-slate-600 text-xl mb-2\">Drop your favorite video</span>\n            <span slot=\"separator\" className=\"text-slate-400 text-sm italic\">— or —</span>\n\n            <MuxUploaderFileSelect muxUploader=\"my-uploader\">\n                <button\n                    className=\"bg-pink-500 hover:bg-pink-600 my-2 px-col-0.5 py-2 rounded-0.125 text-white text-sm\"\n                >\n                    Select from a folder\n                </button>\n            </MuxUploaderFileSelect>\n        </MuxUploaderDrop>\n\n        <MuxUploaderProgress\n            type=\"percentage\"\n            muxUploader=\"my-uploader\"\n            className=\"text-3xl text-orange-600 underline\"\n        />\n    </div>\n  );\n}\n",
      "active": true
    },
    "/src/index.js": {
      "code": "",
      "hidden": true
    }
  },
  "options": {
    "externalResources": [
      "https://cdn.tailwindcss.com"
    ]
  },
  "template": "react"
}
```

## Uploader Page

In this example, we use the Mux Uploader Drop component as the parent for a full page upload experience, with the various subcomponents as descendants
with their own customization for a more bespoke look and feel:

Sandpack interactive code example configuration JSON.stringified:
```json
{
  "customSetup": {
    "dependencies": {
      "@mux/mux-uploader": "latest"
    }
  },
  "files": {
    "/index.html": {
      "code": "<style>\n  /* Various styles to customize a full page upload experience. See below for the HTML usage. */\n  body {\n    margin: 0;\n    color: white;\n    font-family: \"Gill Sans\", sans-serif;\n  }\n\n  /* Hide the uploader since we're only using it for functionality */\n  mux-uploader {\n    display: none;\n  }\n\n  /* Style the drop component as the root container for the page's UI */\n  mux-uploader-drop {\n    padding: 2rem;\n    width: 100vw;\n    height: 100vh;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n    justify-content: flex-start;\n    background: hotpink;\n    /* Style the overlay background based on the page's color palette */\n    --overlay-background-color: purple;\n  }\n\n  /* Use a '+' cursor when dragging over the drop subcomponent */\n  mux-uploader-drop[active] {\n    cursor: copy;\n  }\n\n  mux-uploader-drop > [slot=\"heading\"] {\n    margin: 0;\n  }\n\n  /* Hide the drop component's separator text using its part selector */\n  mux-uploader-drop::part(separator) {\n    display: none;\n  }\n\n  mux-uploader-drop > .main-content {\n    flex-grow: 1;\n    align-self: stretch;\n  }\n\n  /* Use CSS to further customize the file select component's custom button (see below) */\n  mux-uploader-file-select > button {\n    padding: 6px 8px;\n    border: 1px solid #0d9488;\n    border-radius: 5px;\n    font-size: 24px;\n    color: white;\n    background: hotpink;\n    cursor: pointer;\n  }\n\n  mux-uploader-file-select > button:hover {\n    background: purple;\n  }\n\n  /* Customize the progress details to fit with the page's theme, including color palette */\n  mux-uploader-progress {\n    --progress-bar-fill-color: purple;\n    --progress-radial-fill-color: purple;\n    color: purple;\n    --progress-bar-height: 10px;\n  }\n\n  mux-uploader-status {\n    font-family: \"Gill Sans\", sans-serif;\n    font-size: 24px;\n    display: block;\n    padding: 6px 0;\n  }\n\n  /* Update the status component's text color based on the upload state to better fit the page's palette */\n  mux-uploader-status[upload-error] {\n    /* By default, the error text color will be red. */\n    color: navy;\n  }\n\n  mux-uploader-status[upload-complete] {\n    background: dodgerblue;\n  }\n</style>\n\n<!--\n  Note that in this example, mux-uploader is a child of mux-uploader-drop. This is a perfectly valid use case.\n-->\n<mux-uploader-drop\n mux-uploader=\"my-uploader\"\n overlay\n overlay-text=\"Drop to upload\"\n>\n  <mux-uploader\n    no-drop\n    no-progress\n    no-retry\n    no-status\n    id=\"my-uploader\"\n    endpoint=\"https://httpbin.org/put\"\n  ></mux-uploader>\n  <!-- By using the slot, this will automatically get hidden based on upload state changes -->\n  <h1 slot=\"heading\">Drop your video file anywhere on the page</h1>\n  <div class=\"main-content\">\n    <mux-uploader-status mux-uploader=\"my-uploader\"></mux-uploader-status>\n    <mux-uploader-progress mux-uploader=\"my-uploader\" type=\"percentage\"></mux-uploader-progress>\n    <mux-uploader-progress mux-uploader=\"my-uploader\"></mux-uploader-progress>\n  </div>\n  <mux-uploader-file-select mux-uploader=\"my-uploader\">\n    <button>Browse Files</button>\n  </mux-uploader-file-select>\n</mux-uploader-drop>",
      "active": true
    },
    "/index.js": {
      "code": "import '@mux/mux-uploader/dist/mux-uploader.js';",
      "hidden": true
    }
  }
}
```
