How to use Vidstack with Astro

Marius B.Marius B.
6 min read

Integrating Vidstack Video Player with Astro: Three Approaches Compared

Vidstack is a modern, headless video player library that offers excellent customization and performance. When working with Astro, you have several ways to integrate Vidstack into your project. In this post, we'll explore three different approaches, each with their own advantages and trade-offs.

What is Vidstack?

Vidstack is a flexible, framework-agnostic video player that provides both web components and framework-specific integrations. It's designed to be lightweight, accessible, and highly customizable, making it an excellent choice for modern web applications.

Why Astro?

Astro's component-based architecture and excellent performance characteristics make it a great choice for content-heavy sites that need video integration. Its ability to work with multiple frameworks and render static HTML by default aligns well with modern web development practices.

Solution 1: Web Components Approach

This approach uses Vidstack's native web components directly in your Astro templates.

---
// video.astro
import 'vidstack/player/styles/default/theme.css'
import 'vidstack/player/styles/default/layouts/video.css'
import Layout from '../layouts/Layout.astro';

const src = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
const poster = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg"
const title = "Big Buck Bunny";
---

<script>
  import 'vidstack/player'
  import 'vidstack/player/layouts/default'
  import 'vidstack/player/ui'
</script>

<Layout>
  <media-player title={title} src={src} volume={0.2} controls={false} playsInline>
    <media-provider>
      <media-poster class="vds-poster" src={poster}></media-poster>
    </media-provider>
    <media-video-layout></media-video-layout>
  </media-player>
</Layout>

Pros:

  • Framework Agnostic: Works natively with Astro without requiring additional framework integrations

  • Lightweight: No additional JavaScript framework overhead

  • Standards Compliant: Uses native web components that work across all modern browsers

  • Simple Setup: Minimal configuration required, just import and use

  • Server-Side Rendering: Works seamlessly with Astro's SSR capabilities

  • Future Proof: Web components are a web standard and will continue to be supported

Cons:

  • Limited TypeScript Support: Web components don't provide the same level of TypeScript integration as framework-specific components

  • Less Customization: Harder to create complex custom controls compared to framework-specific approaches

  • Event Handling: Managing complex event listeners can be more verbose

  • State Management: No built-in reactive state management like you'd get with framework components

  • Learning Curve: Requires understanding of web component APIs and lifecycle

Solution 2: React Integration

This approach uses Vidstack's React components within Astro's React integration.

---
// video.astro
import 'vidstack/player/styles/default/theme.css'
import 'vidstack/player/styles/default/layouts/video.css'
import Layout from '../layouts/Layout.astro';
import SimpleVideoPlayer from '../components/SimpleVideoPlayer';

const src = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
const poster = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg"
const title = "Big Buck Bunny";
---

<Layout>
  <SimpleVideoPlayer client:load
    src={src}
    poster={poster}
    title={title} />
</Layout>
// SimpleVideoPlayer.tsx
import React from 'react';
import {
  MediaPlayer,
  MediaProvider,
  Poster,
  Track,
  type MediaPlayerInstance,
  type MediaCanPlayDetail,
  type MediaCanPlayEvent,
  type MediaPlayerProps,
} from '@vidstack/react';
import {
  defaultLayoutIcons,
  DefaultAudioLayout,
  DefaultVideoLayout,
} from '@vidstack/react/player/layouts/default';

interface SimpleVideoPlayerProps {
  src: string;
  poster?: string;
  title?: string;
  className?: string;
  subtitles?: Array<{
    src: string;
    label: string;
    language: string;
    default?: boolean;
  }>;
}

export function SimpleVideoPlayer({
  src,
  poster,
  title = "Video Player",
  className = "",
  subtitles = []
}: SimpleVideoPlayerProps) {
  const playerRef = React.useRef<MediaPlayerInstance>(null);

  function onCanPlay(detail: MediaCanPlayDetail, nativeEvent: MediaCanPlayEvent) {
    console.log('Player is ready for playback');
  }

  return (
    <MediaPlayer
      className={`w-full max-w-4xl mx-auto ${className}`}
      title={title}
      src={src}
      crossOrigin
      playsInline
      onCanPlay={onCanPlay}
      ref={playerRef}
    >
      <MediaProvider>
        {poster && <Poster className="vds-poster" src={poster} alt={`${title} poster`} />}

        {subtitles.map((subtitle, index) => (
          <Track
            key={index}
            src={subtitle.src}
            kind="subtitles"
            label={subtitle.label}
            lang={subtitle.language}
            default={subtitle.default}
          />
        ))}
      </MediaProvider>

      <DefaultAudioLayout icons={defaultLayoutIcons} />
      <DefaultVideoLayout icons={defaultLayoutIcons} />
    </MediaPlayer>
  );
}

export default SimpleVideoPlayer;

Pros:

  • Full TypeScript Support: Excellent type safety and autocomplete support

  • Rich Component API: Access to all React-specific features and hooks

  • Advanced State Management: Easy integration with React state management solutions

  • Custom Components: Simple to create complex custom controls and layouts

  • Developer Experience: Better debugging tools and development experience

  • Event Handling: Clean, declarative event handling with React patterns

  • Ecosystem: Access to the entire React ecosystem for additional functionality

Cons:

  • Bundle Size: Adds React runtime overhead to your application

  • Hydration Complexity: Requires client-side hydration, adding complexity

  • Framework Dependency: Ties your video player to React specifically

  • Build Configuration: Requires setting up React integration in Astro

  • Performance: Additional JavaScript bundle size and runtime overhead

  • SSR Limitations: Some React features may not work with Astro's SSR by default

Solution 3: CDN Approach

This approach loads Vidstack directly from a CDN, minimizing build complexity.

---
// video.astro
import Layout from '../layouts/Layout.astro';

const src = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
const poster = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg"
const title = "Big Buck Bunny";
---

<link rel="stylesheet" href="https://cdn.vidstack.io/player/theme.css" />
<link rel="stylesheet" href="https://cdn.vidstack.io/player/video.css" />
<script is:inline src="https://cdn.vidstack.io/player" type="module"></script>

<Layout>
  <media-player title={title} src={src} volume={0.2} controls={false} playsInline>
    <media-provider>
      <media-poster class="vds-poster" src={poster}></media-poster>
    </media-provider>
    <media-video-layout></media-video-layout>
  </media-player>
</Layout>

Pros:

  • Zero Build Configuration: No need to configure bundlers or install npm packages

  • Fast Setup: Get started immediately without any setup

  • CDN Benefits: Leverage CDN caching and global distribution

  • Version Pinning: Easy to pin to specific versions via CDN URLs

  • Minimal Dependencies: No npm dependencies to manage or update

  • Quick Prototyping: Perfect for rapid prototyping and demos

Cons:

  • Network Dependency: Requires internet connection and relies on external CDN availability

  • Version Control: Harder to manage versions and ensure consistency across environments

  • Bundle Optimization: No opportunity for tree shaking or bundle optimization

  • Offline Development: Cannot work offline or in restricted network environments

  • Security Concerns: Potential security risks from loading external scripts

  • Performance Unpredictability: CDN performance can vary based on geographic location and network conditions

  • No TypeScript: Limited or no TypeScript support when loading from CDN

Which Approach Should You Choose?

Choose Web Components (Solution 1) if:

  • You want the simplest, most straightforward integration

  • You're building a mostly static site with minimal interactivity

  • You prefer standards-based solutions

  • You want to avoid additional framework dependencies

  • Bundle size is a primary concern

Choose React Integration (Solution 2) if:

  • You're already using React elsewhere in your Astro project

  • You need complex, interactive video player controls

  • TypeScript support is important to your development workflow

  • You want the best developer experience and tooling

  • You're building a highly interactive application

Choose CDN Approach (Solution 3) if:

  • You're prototyping or building a simple demo

  • You want to get started quickly without any build setup

  • You're working in an environment where you can't install npm packages

  • Network connectivity is reliable and CDN performance is acceptable

  • You don't need advanced bundling optimizations

Conclusion

All three approaches have their place depending on your specific needs. The Web Components approach offers the best balance of simplicity and performance for most Astro projects. The React integration provides the most powerful development experience if you're already committed to React. The CDN approach is perfect for quick setups and prototypes but should be used cautiously in production environments.

Consider your project's requirements, team expertise, and long-term maintenance needs when choosing between these approaches. You can always start with one approach and migrate to another as your needs evolve.

0
Subscribe to my newsletter

Read articles from Marius B. directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marius B.
Marius B.