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

# Web Player Example

The `webPlayer` feature renders an inline pill-shaped control for narrating an article: paragraph-level highlight, click-to-jump navigation, 15-step speed cycle (0.5×–3×), and a sticky mini-player when the main controls scroll out of view. It mounts on every top-level element matching the configured selector, and exposes `rv.webPlayer.mount(selectorOrElement, overrides?)` for content added after `rv.init()`.

> [!TIP]
> [Live demo](https://examples.responsivevoice.org/browser/web-player/) · [Source code](https://github.com/responsivevoice/examples/tree/main/browser/web-player)

## Minimal integration

```html
<script src="https://cdn.responsivevoice.org/sdk/latest/responsivevoice.js"></script>
<script>
  const rv = window.responsiveVoice;
  rv.init({
    features: {
      webPlayer: {
        enabled: true,
        selector: 'article',
        paragraphSelector: 'p, h2, li',
        position: 'before',
        theme: 'responsivevoice',
      },
    },
  });
</script>
```

The feature ships in the CDN bundle — no extra imports.

## Multi-mount

When `selector` matches more than one top-level element, an independent player is mounted on each. Single-active-narrator coordination is implicit: starting playback on one resets every other player to idle.

Nested matches (e.g. `<article>` inside `<article>`) are filtered automatically — only the outermost match mounts. Publishers who specifically want nested mounts write a more specific selector.

## Imperative mount

For SPAs and lazy-loaded sections, call `rv.webPlayer?.mount(selectorOrElement, overrides?)` after the element is in the DOM:

```js
fetch('/article/123')
  .then((r) => r.text())
  .then((html) => {
    document.getElementById('dynamic-area').innerHTML = html;
    const handle = rv.webPlayer?.mount('#dynamic-area', { theme: 'neutral' });
    // later, before removing the element from the DOM:
    // handle?.unmount();
  });
```

Overrides are leaf-merged over the init config — `{ controls: { brand: false } }` keeps the rest of the init defaults intact.

## Skipping content

Any element carrying `data-rv-skip` is excluded from narration:

```html
<article>
  <p>Read this paragraph.</p>
  <div class="pullquote" data-rv-skip>This block is skipped.</div>
  <p>Continue reading from here.</p>
</article>
```

## Next steps

- [Web Player Customization](/examples/web-player-customization) — live control panel for every option.
