Skip to content
FrameworkStyle

Automatically show and hide controls

Show controls while the user is active, hide them during playback, and toggle them by touch.

Show controls while the user is active, fade them out during undisturbed playback, and bring them back on interaction.

Wrap your control UI in Controls. It reads controls visibility from player state, so the whole control bar shows and hides as one unit.

import { Container, Controls, createPlayer, PlayButton, Time } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';

const { Player } = createPlayer({ features: videoFeatures });

export default function BasicUsage() {
  return (
    <Player>
      <Container className="media-container">
        <Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoPlay muted playsInline loop />

        <Controls.Root>
          <Controls.Backdrop className="controls-backdrop" />
          <Controls.Content className="media-controls">
            <Controls.Group className="controls-group" aria-label="Playback controls">
              <PlayButton
                className="button"
                render={(props, state) => <button {...props}>{state.paused ? 'Play' : 'Pause'}</button>}
              />

              <Time.Value type="current" className="time" />
            </Controls.Group>
          </Controls.Content>
        </Controls.Root>
      </Container>
    </Player>
  );
}

How it works

The controls feature tracks activity on the player container:

  • userActive is true while the user interacts — pointer movement, keyboard input, or focus — and flips to false after two seconds of inactivity.
  • controlsVisible derives from activity and playback: controls stay visible while paused or while a remote playback session is connecting or connected, regardless of idle state.
  • toggleControls() flips visibility, for wiring to custom triggers.

On touch devices, a tap on the media toggles the controls instead of relying on pointer movement, and mid-gesture movement doesn’t flicker visibility.

The feature needs the player container for activity tracking; without a container it stays inactive and warns in development.

Availability and constraints

  • Activity tracking listens on the player container, so controls placed outside it don’t keep the player “active” — put control UI inside the container.
  • Keyboard focus counts as activity: controls stay reachable for keyboard and assistive-technology users while focus is inside them.
  • Touch and mouse behave differently by design — mouse movement shows controls, touch requires a tap. Test both.
  • The idle delay is fixed at two seconds.

Common variations

Always-visible controls

Skip the visibility wiring: render your controls without consuming controlsVisible. State still tracks activity for anything else that needs it.

Custom show/hide styling

Controls hide by state, so you own the transition. Style the visible and hidden states in CSS — fade, slide, or scale — driven by the component’s rendered state rather than re-implementing the idle timer.

Troubleshooting

Controls never hide

The media is paused (controls intentionally stay visible), a remote playback session is active, an open menu or popover holds a controls lock, or something keeps triggering activity — for example a focused element inside the container receiving repeated events.

Controls don’t come back on touch

A tap on the media toggles controls. If a custom overlay covers the media and swallows pointer events, taps never reach the container; let pointer events pass through decorative overlays.

Controls flicker on Android while tapping

Use the skin gestures (tap with the toggleControls action) rather than adding your own tap handlers next to the built-in behavior; competing handlers invert each other. See Add keyboard shortcuts and gestures.