# React


A component for embedding Kinescope Player in React. It uses an iframe and the [IFrame API](https://docs.kinescope.com/player-docs/embedding/iframe-api/) under the hood. Repository: [kinescope/react-kinescope-player](https://github.com/kinescope/react-kinescope-player).

## Installation

```bash
npm install @kinescope/react-kinescope-player --save
```

## Quick start

```jsx
import React from 'react'
import KinescopePlayer from '@kinescope/react-kinescope-player'

function Player() {
  return <KinescopePlayer videoId="VIDEO_ID" />
}

export default Player
```

### Events

```jsx
function onTimeUpdate({ currentTime }) {
  console.log(currentTime)
}

<KinescopePlayer videoId="VIDEO_ID" onTimeUpdate={onTimeUpdate} />
```

### Methods

Use a `ref`:

```jsx
const playerRef = React.createRef()

function handleMuteClick() {
  playerRef.current.mute()
}

<>
  <KinescopePlayer ref={playerRef} videoId="VIDEO_ID" />
  <button onClick={handleMuteClick}>Mute</button>
</>
```

### Next.js

The component uses browser APIs, so disable server-side rendering (SSR):

```jsx
import dynamic from 'next/dynamic'

const KinescopePlayer = dynamic(
  () => import('@kinescope/react-kinescope-player'),
  { ssr: false }
)

export default function Player() {
  return <KinescopePlayer videoId="VIDEO_ID" />
}
```

## Props

| Prop | Type | Default | Required |
| :--- | :--- | :--- | :--- |
| `videoId` | `string \| string[]` | — | yes |
| `className` | `string` | — | no |
| `query` | [`Query`](#Query) | — | no |
| `style` | `any` | — | no |
| `preload` | `boolean \| 'none' \| 'metadata' \| 'auto'` | `false` | no |
| `title` | `string` | — | no |
| `subtitle` | `string` | — | no |
| `poster` | `string` | — | no |
| `chapters` | [`Chapter[]`](#Chapter) | — | no |
| `vtt` | [`Vtt[]`](#Vtt) | — | no |
| `width` | `number \| string` | `100%` | no |
| `height` | `number \| string` | `100%` | no |
| `autoPlay` | `boolean \| 'viewable'` | `false` | no |
| `autoPause` | `boolean \| 'reset'` | `true` | no |
| `loop` | `boolean` | `false` | no |
| `playsInline` | `boolean` | `true` | no |
| `muted` | `boolean` | `false` | no |
| `language` | `'en' \| 'ru'` | auto | no |
| `controls` | `boolean` | `true` | no |
| `mainPlayButton` | `boolean` | `true` | no |
| `playbackRateButton` | `boolean` | `false` | no |
| `textTrack` | `boolean \| string` | `true` | no |
| `externalId` | `string` | — | no |
| `drmAuthToken` | `string` | — | no |
| `callToAction` | [`CallToAction[]`](#CallToAction) | — | no |
| `bookmarks` | [`Bookmark[]`](#Bookmark) | — | no |
| `watermark` | [`Watermark`](#Watermark) | — | no |
| `playlistOptions` | [`PlaylistOptions`](#PlaylistOptions) | — | no |
| `theme` | [`Theme`](#Theme) | — | no |
| `localStorage` | [`LocalStorage`](#LocalStorage) | `true` | no |

### Prop types {#prop-types}

#### Chapter {#Chapter}

```ts
type Chapter = {
  position: number
  title: string
}
```

#### Query {#Query}

```ts
type Query = {
  seek?: number
  duration?: number
  playerId?: string
}
```

#### LocalStorage {#LocalStorage}

```ts
type LocalStorage =
  | boolean
  | {
      quality?: 'item' | 'global' | boolean
      time?: boolean
      textTrack?: 'item' | 'global' | boolean
    }
```

#### Vtt {#Vtt}

```ts
type Vtt = {
  label: string
  src: string
  srcLang: string
}
```

#### CallToAction {#CallToAction}

```ts
type CallToAction = {
  id: string
  title: string
  description?: string
  skipable?: boolean
  buttonStyle?: object
  trigger: {
    percentages: number[]
    timePoints: number[]
    pause: boolean
  }
}
```

#### Bookmark {#Bookmark}

```ts
type Bookmark = {
  id: string
  time: number
  title?: string
}
```

#### Watermark {#Watermark}

```ts
type Watermark =
  | string
  | {
      text: string
      mode?: 'random' | 'stripes'
      scale?: number
      displayTimeout?: number | { visible: number; hidden: number }
    }
```

#### PlaylistOptions {#PlaylistOptions}

```ts
type PlaylistOptions = {
  autoSwitch?: boolean
  initialItem?: string
  loop?: boolean
}
```

#### Theme {#Theme}

```ts
type Theme = {
  subtitles?: {
    /** Base font size in em. */
    textScale: number
    textAlign: 'left' | 'center'
    textLength: 'auto' | number
  }
}
```

## Events

| Event | Data |
| :--- | :--- |
| `onJSLoad` | — |
| `onJSLoadError` | — |
| `onInit` | `{ playerId: string }` |
| `onInitError` | `Error` |
| `onReady` | `{ currentTime, duration, quality }` |
| `onQualityChanged` | `{ quality }` |
| `onCurrentTrackChanged` | `{ item: { id?: string } }` |
| `onSeekChapter` | `{ position: number }` |
| `onSizeChanged` | `{ width, height }` |
| `onPlay` | — |
| `onPlaying` | — |
| `onWaiting` | — |
| `onPause` | — |
| `onEnded` | — |
| `onTimeUpdate` | `{ currentTime: number }` |
| `onProgress` | `{ bufferedTime: number }` |
| `onDurationChange` | `{ duration: number }` |
| `onVolumeChange` | `{ muted, volume }` |
| `onPlaybackRateChange` | `{ playbackRate: number }` |
| `onSeeked` | — |
| `onFullscreenChange` | `{ isFullscreen, video }` |
| `onPipChange` | `{ isPip: boolean }` |
| `onCallAction` | `{ id, title?, type }` |
| `onCallBookmark` | `{ id, time, title? }` |
| `onError` | `{ error: unknown }` |
| `onDestroy` | — |

## Methods

Call methods through a `ref`, for example, `playerRef.current.play()`.

| Method | Parameters | Result |
| :--- | :--- | :--- |
| `isPaused` | — | `Promise<boolean>` |
| `isEnded` | — | `Promise<boolean>` |
| `play` | — | `Promise<void>` |
| `pause` | — | `Promise<void>` |
| `stop` | — | `Promise<void>` |
| `getCurrentTime` | — | `Promise<number>` |
| `getDuration` | — | `Promise<number>` |
| `seekTo` | `(time: number)` | `Promise<void>` |
| `isMuted` | — | `Promise<boolean>` |
| `mute` | — | `Promise<void>` |
| `unmute` | — | `Promise<void>` |
| `getVolume` | — | `Promise<number>` |
| `setVolume` | `(value: number)` | `Promise<void>` |
| `getPlaybackRate` | — | `Promise<number>` |
| `setPlaybackRate` | `(value: number)` | `Promise<void>` |
| `getVideoQualityList` | — | `Promise<VideoQuality[]>` |
| `getVideoQuality` | — | `Promise<VideoQuality>` |
| `setVideoQuality` | `(quality: VideoQuality)` | `Promise<void>` |
| `enableTextTrack` | `(lang: string)` | `Promise<void>` |
| `disableTextTrack` | — | `Promise<void>` |
| `closeCTA` | — | `Promise<void>` |
| `isFullscreen` | — | `Promise<boolean>` |
| `setFullscreen` | `(fullscreen: boolean)` | `Promise<void>` |
| `isPip` | — | `Promise<boolean>` |
| `setPip` | `(pip: boolean)` | `Promise<void>` |
| `getPlaylistItem` | — | `Promise<{ id?: string } \| undefined>` |
| `switchTo` | `(id: string)` | `Promise<void>` |
| `next` | — | `Promise<void>` |
| `previous` | — | `Promise<void>` |

See [Control the player](https://docs.kinescope.com/player-docs/embedding/iframe-api-control-player/) for the complete list of IFrame API methods.

## Next steps

- [Vue](https://docs.kinescope.com/player-docs/libraries/vue/)
- [player-iframe-api-loader](https://docs.kinescope.com/player-docs/libraries/player-iframe-api-loader/)
- [IFrame API](https://docs.kinescope.com/player-docs/embedding/iframe-api/)

