# Video Player

A reusable, accessible video player component for embedding and controlling video playback. The component supports various aspect ratios, customizable accessibility labels, and follows form field patterns for error display.

# Rendered Example

# Usage

<template>
  <div>
    <ci-video-player
      src="https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4"
      :controls="true"
      :autoplay="false"
      :muted="false"
      :loop="false"
      poster="https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4"
      aria-label="Demo video player"
      aspect-ratio="16:9"
      ref="videoPlayer"
      @play="onPlay"
      @pause="onPause"
      @ended="onEnded"
      @error="onError"
      @ready="onReady"
      @timeupdate="onTimeUpdate"
      @canplay="onCanPlay"
      @waiting="onWaiting"
    />
    
    <!-- Event feedback example -->
    <div v-if="lastEvent" style="margin-top: 1rem; padding: 0.5rem; background: #e8f5e8; border-radius: 4px;">
      Last event: {{ lastEvent }}
    </div>
    
    <!-- Current time display -->
    <div v-if="currentTime > 0" style="margin-top: 0.5rem; font-size: 0.875rem; color: #666;">
      Current time: {{ formatTime(currentTime) }}
    </div>
  </div>
</template>

<script setup>
import { CiVideoPlayer } from '@ci/stratus-components'
import { ref } from 'vue'

const lastEvent = ref('')
const currentTime = ref(0)
const lastTimeUpdate = ref(0)

function formatTime(seconds) {
  const mins = Math.floor(seconds / 60)
  const secs = Math.floor(seconds % 60)
  return `${mins}:${secs.toString().padStart(2, '0')}`
}

function onPlay() { 
  lastEvent.value = 'Video started playing'
  console.log('Video started playing')
}
function onPause() { 
  lastEvent.value = 'Video paused'
  console.log('Video paused')
}
function onEnded() { 
  lastEvent.value = 'Video playback ended'
  console.log('Video ended')
}
function onError() { 
  lastEvent.value = 'Error occurred while playing video'
  console.log('Video error')
}
function onReady() { 
  lastEvent.value = 'Video is ready to play'
  console.log('Video ready')
}
function onCanPlay() {
  lastEvent.value = 'Video can start playing'
  console.log('Video can play')
}
function onWaiting() {
  lastEvent.value = 'Video is buffering'
  console.log('Video waiting')
}
function onTimeUpdate(event) { 
  const time = event.target.currentTime
  
  // Update current time display
  currentTime.value = time
  
  // Only update last event every 5 seconds for regular playback
  const timeFloor = Math.floor(time)
  if (timeFloor !== lastTimeUpdate.value && timeFloor % 5 === 0) {
    lastTimeUpdate.value = timeFloor
    lastEvent.value = `Current time: ${formatTime(time)}`
  }
}

// Programmatic seek example:
// this.$refs.videoPlayer.seekTo(120) // Seek to 2:00
</script>

# Props

Name Type Default Description
src String β€” Video source URL (required)
controls Boolean true Show native video controls
autoplay Boolean false Autoplay video
muted Boolean false Mute video
loop Boolean false Loop video
poster String '' Poster image URL
currentTime Number 0 Seek to this time (seconds)
ariaLabel String 'Video player' ARIA label for accessibility
aspectRatio String '16:9' Video aspect ratio (16:9, 4:3, 1:1, 21:9)

# Events

Name Payload Description
play β€” Video started playing
pause β€” Video paused
ended β€” Video playback ended
error β€” Error loading/playing video
ready β€” Video metadata loaded
timeupdate Event Native timeupdate event
canplay β€” Video can start playing
waiting β€” Video is buffering

# TimeUpdate Event

The timeupdate event is the native HTML5 video event that fires when the current playback position of the video changes. The event payload is the standard Event object, and you can access the current time via event.target.currentTime.

function onTimeUpdate(event) {
  const currentTime = event.target.currentTime
  console.log(`Current time: ${currentTime} seconds`)
}

# Methods (via ref)

  • seekTo(time: number) β€” Seek to a specific time in seconds.
  • video β€” Access the underlying HTMLVideoElement.

# Accessibility

  • Keyboard and screen reader accessible.
  • ARIA label on the video element.

# Aspect Ratios

The video player supports different aspect ratios to accommodate various video formats and use cases:

<!-- Standard 16:9 aspect ratio (default) -->
<ci-video-player src="video.mp4" aspect-ratio="16:9" />

<!-- Traditional 4:3 aspect ratio -->
<ci-video-player src="video.mp4" aspect-ratio="4:3" />

<!-- Square aspect ratio -->
<ci-video-player src="video.mp4" aspect-ratio="1:1" />

<!-- Ultra-wide 21:9 aspect ratio -->
<ci-video-player src="video.mp4" aspect-ratio="21:9" />

The component uses CSS aspect-ratio to maintain the specified ratio regardless of the video's natural dimensions. The video will scale to fill the container while maintaining the aspect ratio.

# Error Handling

The video player displays error messages below the video player, following form field patterns for consistent styling:

<template>
  <div>
    <!-- Error will appear below the video player -->
    <ci-video-player
      src="invalid-video-url.mp4"
      aria-label="Video with error"
      @error="onError"
    />
  </div>
</template>

<script setup>
function onError() {
  console.log('Video failed to load')
}
</script>

# Error Message Styling

Error messages follow the same styling pattern as form field errors:

  • Appears below the video player (not as an overlay)
  • Uses error color ($error-color)
  • Small text size ($font-size-xs)
  • Left margin for alignment ($space-xs)

# Accessibility

  • Keyboard and screen reader accessible
  • Customizable ARIA label via the ariaLabel prop
  • Error messages appear below the video player following form field patterns
  • Loading indicator handles its own positioning for optimal accessibility

Replace the src prop with your own video URL as needed.

Last Updated: 7/1/2025, 3:29:48 PM