Skip to Content
Mux Docs: Home

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:

<!-- 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:

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:

<style>
  /* Hide the uploader before uploading */
  mux-uploader:not([upload-error]):not([upload-in-progress]):not([upload-complete]) {
    display: none;
  }

  mux-uploader-file-select button {
    background: hotpink;
    color: white;
    padding: 4px 2px;
    border: none;
  }

  mux-uploader-file-select button:hover {
    background: purple;
  }
</style>
<!-- In this example, we're still using Mux Uploader as a visual component -->
<mux-uploader
    id="my-uploader"
    no-drop
    endpoint="https://httpbin.org/put"
  ></mux-uploader>
<mux-uploader-file-select mux-uploader="my-uploader">
  <button>Select from a folder</button>
</mux-uploader-file-select>

Drop

The drop subcomponent is what implements the 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:

<style>
  /* Customize drop area background color & active background color */
  mux-uploader-drop {
    padding: 40px;
    color: white;
    background: hotpink;
  }

  mux-uploader-drop[active] {
    background: #ffe4e6;
  }
</style>

<mux-uploader-drop mux-uploader="my-uploader">
  <!-- Change the heading text/UI shown -->
  <div slot="heading">Drop videoz here plz</div>
  <!-- Remove/hide the separator text/UI (default "Or") -->
  <div slot="separator" style="display: none;"></div>
  <div>You can also add arbitrary children for designs like the drop zone being the full screen</div>
</mux-uploader-drop>
<!-- In this example, we're still using Mux Uploader as a visual component -->
<mux-uploader
    id="my-uploader"
    no-drop
    endpoint="https://httpbin.org/put"
  ></mux-uploader>

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)

Here's an example of these in action:

<style>
  /* Customize drop area background color & overlay background color */
  mux-uploader-drop {
    padding: 40px;
    color: white;
    background: hotpink;
    --overlay-background-color: purple;
  }
</style>

<!-- Use an overlay with customized overlay text -->
<mux-uploader-drop overlay-text="Just let go!" overlay mux-uploader="my-uploader">
  <!-- Change the heading text/UI shown -->
  <div slot="heading">Drop videoz here plz</div>
  <!-- Remove/hide the separator text/UI (default "Or") -->
  <div slot="separator" style="display: none;"></div>
  <div>You can also add arbitrary children for designs like the drop zone being the full screen</div>
</mux-uploader-drop>
<!-- In this example, we're still using Mux Uploader as a visual component -->
<mux-uploader
    id="my-uploader"
    no-drop
    endpoint="https://httpbin.org/put"
  ></mux-uploader>

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.

<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:

<style>
  mux-uploader-progress {
    --progress-bar-fill-color: purple;
    --progress-radial-fill-color: purple;
    color: purple;
    --progress-bar-height: 10px;
  }
</style>
<!-- In this example, we're still using Mux Uploader as a visual component -->
<mux-uploader
    id="my-uploader"
    no-progress
    no-drop
    endpoint="https://httpbin.org/put"
  ></mux-uploader>
  <mux-uploader-progress
  type="percentage"
  mux-uploader="my-uploader"
></mux-uploader-progress>
<mux-uploader-progress
  type="bar"
  mux-uploader="my-uploader"
></mux-uploader-progress>
<mux-uploader-progress
  type="radial"
  mux-uploader="my-uploader"
></mux-uploader-progress>

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 on the status component for additional state-driven styling:

<style>
  mux-uploader {
    height: 2rem;
    padding: 4px 2px;
  }

  mux-uploader-status {
    background: hotpink;
    color: white;
    padding: 4px 2px;
    height: 2rem;
    display: block;
  }

  mux-uploader-status[upload-error] {
    background: crimson;
    /* By default, the error text color will be red. */
    color: white;
  }

  mux-uploader-status[upload-complete] {
    background: dodgerblue;
  }

  mux-uploader-file-select button:hover {
    background: purple;
  }
</style>
<mux-uploader-status mux-uploader="my-uploader"></mux-uploader-status>
<!--
  In this example, we're still using Mux Uploader as a visual component.
  Change the endpoint to an invalid one to see what an error looks like.
-->
<mux-uploader
    id="my-uploader"
    no-drop
    no-status
    endpoint="https://httpbin.org/put"
  ></mux-uploader>

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:

<!-- In this example, we're still using Mux Uploader as a visual component. -->
<mux-uploader
    id="my-uploader"
    no-drop
    no-retry
    endpoint="http://fake.url.for/retry/purposes"
  ></mux-uploader>
<mux-uploader-retry mux-uploader="my-uploader"></mux-uploader-retry>

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:

<!--
  In this example, we're still using Mux Uploader as a visual component.
  We've also made the chunk size smaller to help demo pause/resume behavior.
-->
<mux-uploader
  id="my-uploader"
  no-drop
  chunk-size="512"
  endpoint="https://httpbin.org/put"
></mux-uploader>
<mux-uploader-pause mux-uploader="my-uploader"></mux-uploader-pause>

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 to handle styling of your subcomponents in React. Here's an example of how you can style Mux Uploader using CSS modules:

import styles from "./Styles.module.css";
import MuxUploader, { MuxUploaderFileSelect, MuxUploaderProgress } from "@mux/mux-uploader-react"; 

export default function App() {
  return (
    <div>
        <h2 className={styles.heading}>Mux Uploader with CSS Modules</h2>
        <MuxUploader id="css-modules-uploader" className={styles.uploader} endpoint="https://httpbin.org/put" />
        <MuxUploaderFileSelect muxUploader="css-modules-uploader">
          <button className={styles.button}>Pick your video</button>
        </MuxUploaderFileSelect>
        <MuxUploaderProgress type="percentage" muxUploader="css-modules-uploader" className={styles.progress} />
    </div>
  );
}

React Tailwind CSS

Also like Mux Uploader, you can use Tailwind CSS for your subcomponent styling. Here's an example in React:

import MuxUploader, { MuxUploaderFileSelect, MuxUploaderProgress, MuxUploaderDrop } from "@mux/mux-uploader-react"; 

export default function App() {
  return (
    <div className="p-4">
        <h2 className="text-lg text-slate-800 mb-2 font-bold">Mux Uploader with Tailwind example</h2>
        <MuxUploader id="my-uploader" className="hidden" endpoint="https://httpbin.org/put" />

        <MuxUploaderDrop
            id="my-uploader"
            className="border border-4 border-slate-200 rounded shadow mb-4"
            overlay
            overlayText="Let it go"
        >
            <span slot="heading" className="text-slate-600 text-xl mb-2">Drop your favorite video</span>
            <span slot="separator" className="text-slate-400 text-sm italic">— or —</span>

            <MuxUploaderFileSelect muxUploader="my-uploader">
                <button
                    className="bg-pink-500 hover:bg-pink-600 my-2 px-col-0.5 py-2 rounded text-white text-sm"
                >
                    Select from a folder
                </button>
            </MuxUploaderFileSelect>
        </MuxUploaderDrop>

        <MuxUploaderProgress
            type="percentage"
            muxUploader="my-uploader"
            className="text-3xl text-orange-600 underline"
        />
    </div>
  );
}

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:

<style>
  /* Various styles to customize a full page upload experience. See below for the HTML usage. */
  body {
    margin: 0;
    color: white;
    font-family: "Gill Sans", sans-serif;
  }

  /* Hide the uploader since we're only using it for functionality */
  mux-uploader {
    display: none;
  }

  /* Style the drop component as the root container for the page's UI */
  mux-uploader-drop {
    padding: 2rem;
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    background: hotpink;
    /* Style the overlay background based on the page's color palette */
    --overlay-background-color: purple;
  }

  /* Use a '+' cursor when dragging over the drop subcomponent */
  mux-uploader-drop[active] {
    cursor: copy;
  }

  mux-uploader-drop > [slot="heading"] {
    margin: 0;
  }

  /* Hide the drop component's separator text using its part selector */
  mux-uploader-drop::part(separator) {
    display: none;
  }

  mux-uploader-drop > .main-content {
    flex-grow: 1;
    align-self: stretch;
  }

  /* Use CSS to further customize the file select component's custom button (see below) */
  mux-uploader-file-select > button {
    padding: 6px 8px;
    border: 1px solid #0d9488;
    border-radius: 5px;
    font-size: 24px;
    color: white;
    background: hotpink;
    cursor: pointer;
  }

  mux-uploader-file-select > button:hover {
    background: purple;
  }

  /* Customize the progress details to fit with the page's theme, including color palette */
  mux-uploader-progress {
    --progress-bar-fill-color: purple;
    --progress-radial-fill-color: purple;
    color: purple;
    --progress-bar-height: 10px;
  }

  mux-uploader-status {
    font-family: "Gill Sans", sans-serif;
    font-size: 24px;
    display: block;
    padding: 6px 0;
  }

  /* Update the status component's text color based on the upload state to better fit the page's palette */
  mux-uploader-status[upload-error] {
    /* By default, the error text color will be red. */
    color: navy;
  }

  mux-uploader-status[upload-complete] {
    background: dodgerblue;
  }
</style>

<!--
  Note that in this example, mux-uploader is a child of mux-uploader-drop. This is a perfectly valid use case.
-->
<mux-uploader-drop
 mux-uploader="my-uploader"
 overlay
 overlay-text="Drop to upload"
>
  <mux-uploader
    no-drop
    no-progress
    no-retry
    no-status
    id="my-uploader"
    endpoint="https://httpbin.org/put"
  ></mux-uploader>
  <!-- By using the slot, this will automatically get hidden based on upload state changes -->
  <h1 slot="heading">Drop your video file anywhere on the page</h1>
  <div class="main-content">
    <mux-uploader-status mux-uploader="my-uploader"></mux-uploader-status>
    <mux-uploader-progress mux-uploader="my-uploader" type="percentage"></mux-uploader-progress>
    <mux-uploader-progress mux-uploader="my-uploader"></mux-uploader-progress>
  </div>
  <mux-uploader-file-select mux-uploader="my-uploader">
    <button>Browse Files</button>
  </mux-uploader-file-select>
</mux-uploader-drop>

Was this page helpful?