renderElement
Utility for rendering UI component elements with state-driven props and render prop support
Import
import { renderElement } from '@videojs/react';Usage
renderElement renders a UI component element, handling default tag rendering, render props (element or function), props merging, ref composition, and state-driven className/style.
import { renderElement } from '@videojs/react';
function PlayButton({ className, style, render, ...props }) {
const state = { paused: true };
return renderElement('button', { className, style, render }, {
state,
ref: buttonRef,
props: [{ type: 'button', 'aria-label': 'Play' }, props],
});
} The className and style component props accept either static values or functions that receive the current state:
<PlayButton
className={(state) => state.paused ? 'paused' : 'playing'}
style={(state) => ({ opacity: state.paused ? 0.5 : 1 })}
/> The render prop lets consumers fully customize the rendered element while preserving all internal props and refs:
<PlayButton
render={(props, state) => (
<button {...props}>{state.paused ? 'Play' : 'Pause'}</button>
)}
/>Examples
Basic Usage
import { renderElement } from '@videojs/react';
import { type ReactNode, useState } from 'react';
import './BasicUsage.css';
interface TagState {
active: boolean;
}
function Tag({
className,
style,
render,
active,
children,
}: renderElement.ComponentProps<TagState> & { active: boolean; children?: ReactNode }) {
const state: TagState = { active };
return renderElement(
'span',
{ className, style, render },
{
state,
props: { children },
stateAttrMap: { active: 'data-active' },
}
);
}
export default function BasicUsage() {
const [active, setActive] = useState(false);
const className = (state: TagState) =>
`react-render-element-basic__tag${state.active ? ' react-render-element-basic__tag--active' : ''}`;
const style = (state: TagState) => ({
fontSize: state.active ? '1.125rem' : '0.875rem',
});
return (
<div className="react-render-element-basic">
<button type="button" className="react-render-element-basic__toggle" onClick={() => setActive((prev) => !prev)}>
{active ? 'Deactivate' : 'Activate'}
</button>
<div className="react-render-element-basic__tags">
<Tag active={active} className={className} style={style}>
Default <span>
</Tag>
<Tag active={active} className={className} style={style} render={<strong />}>
Element <strong>
</Tag>
<Tag
active={active}
className={className}
style={style}
render={(props, state) => <em {...props}>{state.active ? 'Active!' : 'Inactive'}</em>}
/>
</div>
</div>
);
}
.react-render-element-basic {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
}
.react-render-element-basic__toggle {
align-self: flex-start;
padding: 6px 16px;
border-radius: 6px;
border: 1px solid #ccc;
background: #f5f5f5;
cursor: pointer;
}
.react-render-element-basic__tags {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.react-render-element-basic__tag {
display: inline-flex;
align-items: center;
padding: 6px 12px;
border-radius: 9999px;
background: #e5e7eb;
color: #374151;
transition: all 0.2s ease;
}
.react-render-element-basic__tag--active {
background: #3b82f6;
color: white;
}
API Reference
Parameters
| Parameter | Type | Default | |
|---|---|---|---|
element* | 'symbol' | 'object' | 'slot' | 'style' | 'title' | 'source' | 'div' | 'search' | 'big' | 'link' | 'small' | 'sub' | 'sup' | 'a' | 'abbr' | 'address' | 'area' | 'article' | 'aside' | 'audio' | 'b' | 'base' | 'bdi' | 'bdo' | 'blockquote' | 'body' | 'br' | 'button' | 'canvas' | 'caption' | 'center' | 'cite' | 'code' | 'col' | 'colgroup' | 'data' | 'datalist' | 'dd' | 'del' | 'details' | 'dfn' | 'dialog' | 'dl' | 'dt' | 'em' | 'embed' | 'fieldset' | 'figcaption' | 'figure' | 'footer' | 'form' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'head' | 'header' | 'hgroup' | 'hr' | 'html' | 'i' | 'iframe' | 'img' | 'input' | 'ins' | 'kbd' | 'keygen' | 'label' | 'legend' | 'li' | 'main' | 'map' | 'mark' | 'menu' | 'menuitem' | 'meta' | 'meter' | 'nav' | 'noindex' | 'noscript' | 'ol' | 'optgroup' | 'option' | 'output' | 'p' | 'param' | 'picture' | 'pre' | 'progress' | 'q' | 'rp' | 'rt' | 'ruby' | 's' | 'samp' | 'script' | 'section' | 'select' | 'span' | 'strong' | 'summary' | 'table' | 'template' | 'tbody' | 'td' | 'textarea' | 'tfoot' | 'th' | 'thead' | 'time' | 'tr' | 'track' | 'u' | 'ul' | 'var' | 'video' | 'wbr' | 'webview' | 'svg' | 'animate' | 'animateMotion' | 'animateTransform' | 'circle' | 'clipPath' | 'defs' | 'desc' | 'ellipse' | 'feBlend' | 'feColorMatrix' | 'feComponentTransfer' | 'feComposite' | 'feConvolveMatrix' | 'feDiffuseLighting' | 'feDisplacementMap' | 'feDistantLight' | 'feDropShadow' | 'feFlood' | 'feFuncA' | 'feFuncB' | 'feFuncG' | 'feFuncR' | 'feGaussianBlur' | 'feImage' | 'feMerge' | 'feMergeNode' | 'feMorphology' | 'feOffset' | 'fePointLight' | 'feSpecularLighting' | 'feSpotLight' | 'feTile' | 'feTurbulence' | 'filter' | 'foreignObject' | 'g' | 'image' | 'line' | 'linearGradient' | 'marker' | 'mask' | 'metadata' | 'mpath' | 'path' | 'pattern' | 'polygon' | 'polyline' | 'radialGradient' | 'rect' | 'set' | 'stop' | 'switch' | 'text' | 'textPath' | 'tspan' | 'use' | 'view' | — | |
componentProps* | UseRenderComponentProps<{}> | — | |
params* | UseRenderParameters<{}, Element> | — |
Return Value
ReactElement