FrameworkStyle

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

Default <span>Element <strong>Inactive
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 &lt;span&gt;
        </Tag>

        <Tag active={active} className={className} style={style} render={<strong />}>
          Element &lt;strong&gt;
        </Tag>

        <Tag
          active={active}
          className={className}
          style={style}
          render={(props, state) => <em {...props}>{state.active ? 'Active!' : 'Inactive'}</em>}
        />
      </div>
    </div>
  );
}

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

VideoJS