--- title: "플레이어 UI" slug: "vpe-react-player-ui" updated: 2026-09-17T09:08:03Z published: 2026-09-17T09:08:03Z canonical: "guide.ncloud-docs.com/vpe-react-player-ui" stale: true --- > ## Documentation Index > Fetch the complete documentation index at: https://guide.ncloud-docs.com/llms.txt > Use this file to discover all available pages before exploring further. # 플레이어 UI Classic/VPC 환경에서 이용 가능합니다. 스크립트 코드를 수정하여 UI와 관련된 옵션을 설정하는 방법을 설명합니다. 참고 - 옵션을 설정하는 속성에 대한 설명은 플레이어 설정을 참고해 주십시오. - 이용 중인 요금제에 따라 설정 가능한 옵션이 다를 수 있습니다. ## 기본 옵션 ### aspectRatio (화면 비율) 플레이어 영역의 화면 비율을 설정합니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### objectFit (화면 채움) 비디오가 영역에 맞춰지는 방식을 설정합니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### language (다국어) 플레이어에서 사용하는 언어를 설정합니다. 설정하지 않으면 브라우저에서 사용하는 언어를 따라갑니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ## 컨트롤바 ### controls (컨트롤바 표시) 기본 컨트롤바 UI의 표시 여부를 설정합니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### controlBtn (컨트롤바 버튼 UI) 컨트롤바 버튼 표시/숨김을 개별적으로 설정합니다. 참고 Standard 요금제에서만 사용할 수 있습니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### progressBarColor (컨트롤바 색상) 컨트롤바 진행 색상을 설정합니다. 참고 Standard 요금제에서만 사용할 수 있습니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### controlActiveTime (컨트롤바 표시 시간) 컨트롤바가 표시되는 시간을 설정합니다. 참고 `controlActiveTime: 0` 으로 설정하면 컨트롤바가 자동으로 숨겨지지 않고 항상 표시됩니다. 라이브커머스처럼 UI가 늘 보여야 하는 화면에 유용합니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### ui (컨트롤바 UI 고정) UI 타입을 지정합니다. 참고 Standard 요금제에서만 사용할 수 있습니다. - 모바일 UI는 `touchGestures`, PC UI는 `keyboardShortcut`을 제공합니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ## 자막 ### 자막 설정 (VTT) VTT 자막을 연결합니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 동영상(MP4) export function App() { return ( ); } ``` ### captionType (자막 렌더링 방식) 자막을 어떻게 그릴지 결정하는 옵션입니다. `"html"` (기본), `"native"` 중 선택할 수 있으며, 디자인 일관성을 우선할지 OS 접근성 설정을 우선할지에 따라 달라집니다. | 항목 | `"html"` (기본) | `"native"` | | --- | --- | --- | | 렌더링 주체 | SDK가 플레이어 위에 직접 `<div>`로 자막을 그림 | 브라우저/OS의 기본 `::cue` 렌더링을 사용 | | captionStyle 옵션 | 모두 적용됨 (인라인 스타일로 직접 제어) | 무시됨 (브라우저별 `::cue` 지원 차이로 일관된 스타일링 불가) | | OS 접근성 자막 설정 | 영향 없음 (모바일 네이티브 자막 UI는 `track.mode="hidden"`으로 차단되어 일관된 스타일이 유지됨) | 그대로 반영됨 (iOS **설정 > 손쉬운 사용 > 자막 및 자막 사용**, Android **설정 > 접근성 > 자막 환경설정**을 그대로 따라감) | | 추천 케이스 | 디자인 일관성 우선 (다크모드 UI, 브랜드 컬러 자막 등) | 웹 접근성 우선 (시각 보조 정책상 OS 접근성 설정을 반드시 따라가야 하는 서비스) | 참고 웹 접근성(WCAG) 가이드라인에 따라 자막 글꼴, 크기, 색상은 사용자가 직접 조정할 수 있어야 합니다. `captionType: "native"`는 OS가 제공하는 접근성 자막 환경설정을 그대로 반영하므로, 시각 보조가 필요한 사용자에게 가장 가까운 경험을 제공합니다. **html 모드: captionStyle로 직접 스타일링 (기본)** ``` ``` **native 모드: OS 접근성 자막 설정을 그대로 따라감** ``` ``` ### captionStyle (자막 스타일) 자막의 폰트 크기, 색상, 배경, 가장자리 처리, 행간, 위치 등을 옵션으로 직접 설정합니다. `captionType`이 `"html"` (기본)일 때만 적용되며, `"native"` 모드에서는 무시됩니다. 브랜드 컬러, 다크모드 UI 등 일관된 자막 스타일링이 필요할 때 사용할 수 있습니다. ``` ``` **captionStyle 속성** 미지정 시 기본값이 자동 적용되며, 옵션 전달 시 기본값과 deep-merge 됩니다. (예: `{ fontSize: 20 }`만 넘기면 `fontSize=20` + 나머지는 기본값) 반응형 분기: `fontSize`, `lineHeight`, `bottomOffset`, `sidePadding`는 단일 값 또는 `{ pc, mobile }` 객체로 지정할 수 있습니다. | 속성 | 타입 | 기본값 | 설명 | | --- | --- | --- | --- | | `fontSize` | `number \| string \| { pc?, mobile? }` | `{ pc: 20, mobile: 14 }` | 자막 폰트 크기 (px/CSS 단위). PC/모바일 분기 지원 | | `fontFamily` | `string` | — | 자막 폰트 (CSS font-family) | | `color` | `string` | `#ffffff` | 자막 글자 색상 (CSS 색상값) | | `backgroundColor` | `string` | `transparent` | 자막 박스 배경색. 예: `rgba(0,0,0,0.4)` | | `opacity` | `number` | `1` | 자막 텍스트 전체 불투명도 (0~1) | | `lineHeight` | `number \| string \| { pc?, mobile? }` | `{ pc: 1.3, mobile: 1.2 }` | 자막 행간 (배수). PC/모바일 분기 지원 | | `edgeStyle` | `none \| dropshadow \| raised \| depressed \| uniform` | `uniform` | 텍스트 가장자리 처리 방식 (밝은/어두운 영상 모두 가독성 우수) | | `bottomOffset` | `number \| { pc?, mobile? }` | `{ pc: 30, mobile: 10 }` | 플레이어 하단으로부터 간격 (px). 컨트롤바와 겹치지 않게 조정. PC/모바일 분기 지원 | | `sidePadding` | `number \| { pc?, mobile? }` | `{ pc: 60, mobile: 40 }` | 좌/우 안전 영역 (px). PC/모바일 분기 지원 | | `padding` | `number \| string` | `3px 5px` | 자막 텍스트 박스 내부 패딩 (CSS padding 값) | 참고 edgeStyle 종류: `none` (효과 없음) / `dropshadow` (그림자) / `raised` (솟아 보이는 효과) / `depressed` (들어가 보이는 효과) / `uniform` (4방향 외곽선, 기본 권장) ## 레이아웃 시스템 레이아웃 시스템을 사용하면 컨트롤바의 버튼 배치, 영역 구성, 커스텀 컴포넌트 삽입을 JSON 기반으로 선언적으로 정의할 수 있습니다. 화면 환경별(PC/모바일/전체화면)과 콘텐츠 유형별(VOD/Live)을 각각 분리해 관리할 수 있습니다. 참고 - Standard 요금제에서만 사용할 수 있습니다. - 레이아웃 JSON은 [UI Editor](https://vpe-player-editor.web.app/)에서 시각적으로 편집하고 결과를 그대로 코드에 적용할 수 있습니다. 자세한 구조와 속성은 [레이아웃 시스템 가이드](https://developer.vpe.naverncp.com/docs/layout-system)를 참조해 주십시오. ### 기본 레이아웃 구성 `order`로 섹션 순서를 정하고, 각 섹션에 Row를 배치합니다. Row의 `items`에 빌트인 컴포넌트나 커스텀 요소를 넣을 수 있습니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; const layout = { pc: { vod: { order: ["top", "center", "bottom"], top: [{ items: ["MetaDesc"] }], center: [{ items: ["BigPlayBtn"], align: "center" }], bottom: [ { items: ["ProgressBar"] }, { items: ["PlayBtn", "VolumeBtn", "TimeBtn"], wrapper: "Group" }, { wrapper: "Blank", items: [] }, { items: ["SettingBtn", "PipBtn", "FullscreenBtn"], wrapper: "Group" }, ], }, }, }; export function App() { return ( ); } ``` ### 레이아웃 타입 `layout` prop은 다음 3가지 형태로 전달할 수 있습니다. ``` // 1) 단일 레이아웃 — 라이브/VOD/디바이스 분기 없이 하나의 컨트롤바 구성 type ControlBarLayout = { order?: string[]; top?: Group[]; upper?: Group[]; center?: Group[]; lower?: Group[]; bottom?: Group[]; }; // 2) 라이브 / VOD 분기 type ControlBarLayoutVariant = { live: ControlBarLayout; vod: ControlBarLayout; }; // 3) 반응형 (PC / Mobile / Fullscreen 분기) type ControlBarLayoutResponsive = { pc: { live: ControlBarLayout; vod: ControlBarLayout }; mobile: { live: ControlBarLayout; vod: ControlBarLayout }; fullscreen: { live: ControlBarLayout; vod: ControlBarLayout }; breakpoint?: number; // 기본 768 }; ``` ### 구성 구조 최상위 키는 `pc`, `mobile`, `fullscreen`으로 나뉘며, 각 환경 내부에 `vod`와 `live` 레이아웃을 정의합니다. ``` { "pc": { "vod": { }, "live": { } }, "mobile": { "vod": { }, "live": { } }, "fullscreen": { "vod": { }, "live": { } } } ``` `layout.json` ### 섹션과 순서 `order` 배열이 렌더링 순서를 결정합니다. 기본 섹션은 `top`, `upper`, `center`, `lower`, `bottom`입니다. ``` { "order": ["top", "upper", "center", "lower", "bottom"], "top": [ { "items": ["MetaDesc"] }, { "wrapper": "Blank", "items": [], "align": "left" }, { "items": ["ShareBtn"] } ], "center": [ { "items": ["BigPlayBtn"], "align": "center" } ], "bottom": [ { "items": ["ProgressBar"] }, { "items": ["PlayBtn", "VolumeBtn", "TimeDisplay"], "align": "left" }, { "items": ["SettingBtn", "PIPBtn", "FullscreenBtn"], "align": "right" } ] } ``` `pc.vod.json` ### 행(Row) 구성 각 섹션은 여러 개의 Row로 구성됩니다. Row는 `items` 배열을 통해 버튼이나 컴포넌트를 배치하고, `align`과 `wrapper`로 정렬과 묶음 방식을 조정합니다. | 키 | 타입 | 설명 | | --- | --- | --- | | `key` | `string` | Group 식별자. 런타임 `layout()` 머지 시 같은 `key`의 Group끼리 교체 (권장) | | `items` | `(string \| ReactNode)[]` | Row에 배치할 컨트롤 목록 (빌트인 키 또는 커스텀 컴포넌트) | | `align` | `left \| center \| right` | Row 내 콘텐츠 정렬 방식 | | `wrapper` | `"Group" \| "Blank"` | Row에 적용할 래퍼 타입 (Group=묶음, Blank=빈 공간/간격) | | `cap` | `number` | Row 내 표시 아이템 수 제한 | | `noPadding` | `boolean` | Group 좌우 패딩 제거 | ### 기본 레이아웃 예제 각 Group에 `key`를 지정하면 런타임 머지 시 특정 Group만 안전하게 교체할 수 있습니다. ``` const layout: ControlBarLayout = { top: [], center: [{ key: "bigPlayBtn", items: ["BigPlayBtn"] }], bottom: [ { key: "play", items: ["PlayBtn"], wrapper: "Group", noPadding: true }, { key: "volume", items: ["VolumeBtn"], wrapper: "Group" }, { key: "time", items: ["TimeBtn"], wrapper: "Group" }, { key: "blank", wrapper: "Blank", items: [] }, { key: "right", items: ["SubtitleBtn", "FullscreenBtn"], cap: 2, wrapper: "Group" }, ], }; ``` ### 커스텀 컴포넌트 삽입 레이아웃의 `items` 배열에 빌트인 키 대신 직접 만든 컴포넌트를 전달하면 컨트롤바 내 원하는 위치에 커스텀 UI를 배치할 수 있습니다. ``` import Hls from "hls.js"; import dashjs from "dashjs"; import { VpePlayer } from "@sgrsoft/vpe-react-sdk"; // 커스텀 로고 컴포넌트 function Logo() { return ( ); } const layout = { pc: { vod: { order: ["top", "center", "bottom"], top: [{ items: ["MetaDesc"] }], center: [{ items: ["BigPlayBtn"], align: "center" }], bottom: [ { items: ["PlayBtn", "PrevBtn", "NextBtn"], wrapper: "Group" }, { items: ["VolumeBtn"], wrapper: "Group" }, { items: ["TimeBtn"], wrapper: "Group" }, { wrapper: "Blank", items: [] }, { items: [Logo()], wrapper: "Group" }, // 커스텀 컴포넌트 { items: ["SubtitleBtn", "PipBtn", "SettingBtn", "FullscreenBtn"], cap: 2, wrapper: "Group" }, ], }, }, }; export function App() { return ( ); } ``` ### 실시간 변경 (ref) `playerRef.current?.layout(nextLayout, merge?)`를 호출해 재생 중에도 레이아웃을 동적으로 변경할 수 있습니다. 두 번째 인자 `merge`의 기본값은 `true`입니다. **머지 규칙 (merge: true)** 1. `top` / `upper` / `center` / `lower` / `bottom` / `order` 중 next에 정의되지 않은 section은 base 유지 2. section 내 Group 머지는 `key` 기반: - base와 next에 같은 key의 Group → next로 교체 - base에만 있는 key → base 유지 - next에만 있는 key → 결과 끝에 append - next에 key 없는 Group → 결과 끝에 append (신규 추가로 간주) 3. 양쪽 Group 모두 key가 없으면 → section 통째 교체 (하위 호환) **예시: 특정 Group만 교체** ``` // base (default pcLayout.vod) // bottom: [ // { key: "play", items: ["PlayBtn"] }, // { key: "volume", items: ["VolumeBtn"] }, // { key: "time", items: ["TimeBtn"] }, // { key: "blank", wrapper: "Blank", items: [] }, // { key: "right", items: ["SubtitleBtn", "FullscreenBtn"] }, // ] playerRef.current?.layout({ bottom: [{ key: "right", items: ["SubtitleBtn", "PipBtn", "SettingBtn", "FullscreenBtn"] }], }); // 결과: play/volume/time/blank 유지, right만 교체 ``` **예시: 새 Group 추가** ``` playerRef.current?.layout({ bottom: [{ key: "extra", items: ["ShareBtn"] }], }); // 결과: 기존 5개 Group + 끝에 extra(ShareBtn) append ``` **예시: section 전체 교체 (merge: false)** ``` playerRef.current?.layout( { bottom: [{ items: ["PlayBtn"] }] }, false, // 통째로 교체 ); ```