# react-h5-audio-player: a React player with its own UI, keyboard control and mobile defaults

> react-h5-audio-player is a TypeScript React component that replaces the browser's native audio controls with a customisable player, with a time indicator, keyboard shortcuts, flexbox and SVG icons, and support for Media Source Extensions and Encrypted Media Extensions. It suits a React app that needs a consistent player across browsers, and it does not play HLS or DRM streams without additional work.

**lhz516/react-h5-audio-player** — React audio player component with UI. It provides time indicator on both desktop and mobile devices.

- Repository: https://github.com/lhz516/react-h5-audio-player
- Website: https://codepen.io/lhz516/pen/dyGpmgP
- Stars: 694 · Forks: 103
- Language: JavaScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/lhz516-react-h5-audio-player

## The component replaces the native controls rather than styling them

react-h5-audio-player is described as an audio player component that provides consistent UI and UX on different browsers. That is the problem it solves. The native HTML audio element renders its own controls, and those controls look different in Chrome, Firefox, Safari and Edge, and on a phone they are a sheet that slides up from the bottom of the screen with a different set of buttons again.

The feature list sets out how the component answers that. The layout is super customizable, the CSS is flexbox with SVG icons, and it is mobile friendly. Internationalisation and accessibility are supported, as are keyboard events. It is written in TypeScript. And it supports Media Source Extensions and Encrypted Media Extensions, which is the part that makes it more than a skin.

The usage example is short enough to read in full:

```jsx
import AudioPlayer from 'react-h5-audio-player';
import 'react-h5-audio-player/lib/styles.css';

const Player = () => (
  <AudioPlayer
    autoPlay
    src="http://example.com/audio.mp3"
    onPlay={e => console.log("onPlay")}
    // other props here
  />
);
```

Two details in that snippet matter. The stylesheet is a separate import, so the component ships CSS you have to load, and the props are the native audio element's props, so a src and an autoPlay mean what they mean in HTML.

There is one instruction about the native attributes that is worth reading twice. The controls attribute defaults to false and should never be changed to true, because the library is already providing UI. Set it and you have the native controls and the custom controls on the same element.

## The keyboard layer is a first class part of the API

The component ships keyboard shortcuts, and they can be turned off with a prop, hasDefaultKeyBindings, set to false. The bindings apply when the audio player has focus.

Space is play and pause, the left and right arrows rewind and forward, the up and down arrows change the volume, L toggles loop, and M toggles mute. That is a sensible set, and it is the set a player needs to be usable without a mouse.

The jump distances are configurable rather than fixed, which is what makes this usable in a product rather than a demo. volumeJumpStep is a number, defaulting to 0.1, and it indicates the volume jump step when pressing the up or down arrow key, with the volume range being 0 to 1. progressJumpSteps is an object that defaults to { backward: 5000, forward: 5000 }, in milliseconds, and it governs both the rewind and forward buttons and the left and right arrow keys. So a five second skip by default, and a different number if your content is a podcast with long silences.

The time indicator is handled by three related props. defaultCurrentTime and defaultDuration are ReactNode values that both default to the string '--:--', and they are what is displayed before the source's metadata has loaded. timeFormat accepts 'auto', 'mm:ss' or 'hh:mm:ss' and defaults to 'auto', where auto means that when the duration is greater than one hour the format is hh:mm:ss and otherwise it is mm:ss.

The repository description mentions the time indicator on both desktop and mobile devices, and that is the feature the component is named for in the description of what it provides.

## The layout is assembled from named sections you can rearrange

The customisation model is the most interesting part of the prop surface, and it is not the usual set of booleans.

There are four customisation props, and each of them takes an array of section names rather than a rendered element. customProgressBarSection takes an array of strings or React elements and defaults to CURRENT_TIME, PROGRESS_BAR and DURATION. customControlsSection takes an array of strings or React elements and defaults to ADDITIONAL_CONTROLS, MAIN_CONTROLS and VOLUME_CONTROLS. customAdditionalControls takes an array of strings or React elements and defaults to LOOP. And customVolumeControls takes an array of strings or React elements.

So a product team does not restyle the player by overriding CSS classes, they describe which pieces go where. The progress bar is a section you can reorder, and the same is true of the controls. The customIcons prop is the exception, a map of icon overrides that replaces the default ones.

Alongside that sits the layout prop, which takes 'stacked', 'horizontal', 'stacked-reverse' or 'horizontal-reverse' and defaults to 'stacked', with the four arrangements covering the two axes and their reversals.

The remaining boolean props control what is visible. showSkipControls, defaulting to false, shows the previous and next buttons. showJumpControls, defaulting to true, shows the rewind and forward buttons. showDownloadProgress, defaulting to true, shows download progress over the progress bar, and showFilledProgress, also defaulting to true, shows the already-played area. showFilledVolume defaults to false and shows the filled area on the volume bar.

Header and footer are both ReactNode and both default to null, so the player can be dropped into a card or a page section without a wrapper element.

## The native attributes pass through, with two that behave badly on phones

The prop table for the HTML audio tag's native attributes is mostly a restatement of the platform, and reading it is useful for the two rows that are not.

src is a string defaulting to an empty string. preload takes 'auto', 'metadata' or 'none' and defaults to 'auto'. loop and muted are booleans defaulting to false. volume is a number defaulting to 1.0. crossOrigin and mediaGroup are strings defaulting to undefined.

The two exceptions are the ones with notes attached, and they are the same two people hit immediately. autoPlay carries the note that it will not work on most mobile devices, and volume carries the same warning. Browsers on phones block autoplay until the user has interacted with the page, and volume set from markup is ignored on the same platforms.

That is not a bug in the component, it is the platform, and the component is honest about it. It does mean that a player whose playback depends on an autoPlay prop will appear broken on a phone for reasons that have nothing to do with your code.

There is also autoPlayAfterSrcChange, which defaults to true and plays the audio after the src is changed, no matter what the value of autoPlay is. That is the sensible behaviour for a player in a React app where the track changes in place, and it is the prop to reach for if you were worried that changing sources would stop the audio.

The progressUpdateInterval prop controls how often the progress bar UI updates, in milliseconds, with a default of 20, and listenInterval controls how often the onListened prop is called during playback, defaulting to 1000. The first is a rendering cost knob and the second is an analytics knob.

## Building it, and the difference between the v3 and v4 packages

The install command depends on which line you are taking, and the documentation is explicit about it. Install with @next for v4, and without @next for v3.

```bash
npm i react-h5-audio-player@next
```

or with yarn:

```bash
yarn add react-h5-audio-player@next
```

That split is the current state of the project rather than a design choice you can ignore. The most recent release is v4.0.0-rc.1 from 2025-12-25, and the package.json in the repository is at 4.0.0-rc.5, so the v4 line is still a release candidate while the v3 line has a 3.10.2 published on 2026-03-07. A project that needs a stable dependency today is on v3, and a project that wants the v4 API is tracking a pre-release tag, and there is a migration guide linked from the readme for moving between them.

The build itself is a Babel and Vite pipeline producing several output formats, which is what a library that has to work in both bundler and script-tag contexts needs. The build script runs the CommonJS, type declaration, ES module, UMD and CSS steps in parallel, and the outputs land in lib/ and es/ with the package entry points pointing at ./lib/index.js for main, ./es/index.js for module and ./lib/index.d.ts for types. The stylesheet is copied from src/styles.css into lib/styles.css, which is why the usage example imports it from the lib path rather than the source path.

The development setup is Storybook, on port 9000, with the stories/ directory in the tree, and the live demo linked from the readme is that Storybook deployment. There are also CodePen examples for a basic player and for a playlist, which is a quick way to see what the component looks like before installing anything. Tests run under Vitest with a UI mode and a coverage script, and the supported browsers are listed as Chrome, Firefox, Safari and Edge.

## Where react-h5-audio-player is the wrong tool

The first limit is the licensing and the shape of the API. This is MIT licensed and permissive, but the component comes with a stylesheet that has to be loaded and a prop surface that is large, with around twenty layout and behaviour knobs. For a site that needs a play button and a progress bar, the native audio element with the controls attribute is a handful of markup and no dependency, and this library is the heavier answer to a lighter question.

The second limit is what it does not implement. The component supports Media Source Extensions and Encrypted Media Extensions, which means it can sit in front of a segmented media pipeline and a DRM pipeline, but that is a capability, not a solution. The media handling, the segment loader, the licence server and the key exchange are still yours to build, and the same is true for adaptive streaming formats over MSE. If what you are shipping is HLS, the work is in your player, not in this component.

The third is the v4 release candidate. Installing @next means your build follows a pre-release, and the migration guide between v3 and v4 exists because something changed. For a component that touches every page of a product, that is a real maintenance commitment, and the version pinning in your lockfile becomes the thing standing between you and an upstream breaking change.

The fourth is the mobile behaviour, and it is the one that surprises people. autoPlay and volume do not work on most mobile devices, and the component says so rather than working around it. If your product depends on playing a track the moment a user lands, the native element will not do that either, so the constraint is shared, but it does mean the autoPlay prop is not something you can rely on across the platforms the component claims to support.

The fifth is the styling contract. The component ships its own CSS, and the layout is described as flexbox with SVG icons. If your design system has its own spacing, icon set and control styling, the customisation props cover the structure and the icons, but the visual language of the buttons, the tracks and the typography is the library's, and overriding it means fighting the shipped stylesheet rather than configuring the component.

## Conclusion

react-h5-audio-player is worth adopting for a React product that needs one player that looks the same in every browser and works on a phone, because the component ships its own controls, its own styling and a keyboard layer, and because the layout system is per-section so a product team can change the progress bar without forking the component. It is the wrong choice for a project that just needs a bare audio element, since the native element is a line of markup and this is a dependency with a stylesheet, a prop surface and a v4 migration to plan. Before you adopt it, check the three things the documentation is explicit about: that the controls attribute defaults to false and should never be set to true, because the library is already providing the UI and you would end up with two players on the page; that autoPlay and volume will not work on most mobile devices, as the prop table states; and that v4 is still a release candidate, so the install command for the current line is the @next tag while the v3 line installs without it, and the two are not interchangeable.

## FAQ

### How do I install react-h5-audio-player?

Install with the @next tag for v4 and without it for v3, for example npm i react-h5-audio-player@next or yarn add react-h5-audio-player@next. The v4 line is still a release candidate, so a project that wants a stable release takes the v3 package instead.

### What keyboard shortcuts does react-h5-audio-player support?

When the player has focus, Space plays and pauses, the left and right arrows rewind and forward, the up and down arrows change the volume, L toggles loop and M toggles mute. The bindings can be disabled by setting the hasDefaultKeyBindings prop to false, and the jump distances are configurable through progressJumpSteps and volumeJumpStep.

### Can I change the layout of the react-h5-audio-player controls?

Yes. The customisation props take arrays of section names or React elements, so customProgressBarSection defaults to CURRENT_TIME, PROGRESS_BAR and DURATION, customControlsSection defaults to ADDITIONAL_CONTROLS, MAIN_CONTROLS and VOLUME_CONTROLS, and customAdditionalControls defaults to LOOP. The layout prop separately sets stacked, horizontal or either of those reversed.

## Sources

- [lhz516/react-h5-audio-player on GitHub](https://github.com/lhz516/react-h5-audio-player)
- [License: MIT](https://github.com/lhz516/react-h5-audio-player/blob/master/LICENSE)
- [Project website](https://codepen.io/lhz516/pen/dyGpmgP)
- [README](https://github.com/lhz516/react-h5-audio-player/blob/master/README.md)
- [Releases](https://github.com/lhz516/react-h5-audio-player/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lhz516-react-h5-audio-player
