limeplay
uicaptionssource: ok · hit
Captions
npx shadcn add "https://limeplay.winoffrg.dev/r/captions.json"free
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightui-primitives@radix-ui/react-compose-refs@radix-ui/react-slot
Registry dependencies
https://limeplay.winoffrg.dev/r/media-provider.jsonhttps://limeplay.winoffrg.dev/r/use-captions.json
Files1 · source cached 10/14/2026, 1:36:04 PM
registry/default/ui/captions.tsx
"use client"
import { composeRefs } from "@radix-ui/react-compose-refs"
import { Slot } from "@radix-ui/react-slot"
import React, { useEffect } from "react"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import {
useCaptions,
useCaptionsStore,
} from "@/registry/default/hooks/use-captions"
import { usePlayerStore } from "@/registry/default/hooks/use-player"
export interface CaptionsControlProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
/**
* Render as child component using Radix Slot
* @default false
*/
asChild?: boolean
render?: React.ReactElement
/**
* Keyboard shortcut hint displayed in aria-label
* @example "C"
*/
shortcut?: string
}
export type CaptionsControlPropsDocs = Pick<
CaptionsControlProps,
"asChild" | "render" | "shortcut"
>
export const CaptionsControl = React.forwardRef<
HTMLButtonElement,
CaptionsControlProps
>((props, forwardedRef) => {
const textTracks = useCaptionsStore((state) => state.tracks)
const { toggleVisibility } = useCaptions()
const {
"aria-label": ariaLabelProp,
asChild = false,
children,
disabled: userDisabled,
onClick,
render,
shortcut,
...restProps
} = props
const Comp = render ? Slot : asChild ? Slot : Button
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
onClick?.(event)
if (!event.defaultPrevented) {
toggleVisibility()
}
}
const isDisabled = !textTracks || textTracks.length === 0 || userDisabled
const getDefaultAriaLabel = () => {
const shortcutText = shortcut ? ` (keyboard shortcut ${shortcut})` : ""
return `Captions${shortcutText}`
}
return (
<Comp
aria-keyshortcuts={shortcut}
aria-label={ariaLabelProp ?? getDefaultAriaLabel()}
data-label="lp-captions-control"
disabled={isDisabled}
{...restProps}
onClick={handleClick}
ref={forwardedRef}
>
{render ? React.cloneElement(render, undefined, children) : children}
</Comp>
)
})
CaptionsControl.displayName = "CaptionsControl"
export type CaptionsContainerPropsDocs = Pick<
CaptionsContainerProps,
"fontScale"
>
interface CaptionsContainerProps extends React.ComponentPropsWithoutRef<"div"> {
/**
* Font scale factor for caption text size
* @default 1
*/
fontScale?: number
}
export const CaptionsContainer = React.forwardRef<
HTMLDivElement,
CaptionsContainerProps
>((props, ref) => {
const { className, fontScale, ...etc } = props
const player = usePlayerStore((state) => state.instance)
const setContainerElement = useCaptionsStore(
(state) => state.setContainerElement
)
useEffect(() => {
if (player && fontScale) {
player.configure({
textDisplayer: {
fontScaleFactor: fontScale,
},
})
}
}, [player, fontScale])
return (
<div
className={cn(
"relative flex w-full grow flex-col justify-end text-lg",
className
)}
ref={composeRefs(ref, setContainerElement)}
{...etc}
/>
)
})
CaptionsContainer.displayName = "CaptionsContainer"