# renderElement

Utility for rendering UI component elements with state-driven props and render prop support

## Import

```tsx
import { renderElement } from "@videojs/react";
```

`renderElement` renders a UI component element, handling default tag rendering, render props (element or function), props merging, ref composition, and state-driven `className`/`style`.

**PlayButton.tsx**

```tsx
import { useRef } from "react";
import { renderElement } from "@videojs/react";

function PlayButton({ className, style, render, ...props }) {
  const buttonRef = useRef<HTMLButtonElement>(null);
  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:

```tsx
<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:

```tsx
<PlayButton
  render={(props, state) => (
    <button {...props}>{state.paused ? "Play" : "Pause"}</button>
  )}
/>
```

## Examples

### Basic Usage

**App.tsx**

```tsx
import { renderElement } from '@videojs/react';
import { type ReactNode, useState } from 'react';

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) => `tag${state.active ? ' tag--active' : ''}`;

  const style = (state: TagState) => ({
    fontSize: state.active ? '1.125rem' : '0.875rem',
  });

  return (
    <div className="demo">
      <button type="button" className="toggle" onClick={() => setActive((prev) => !prev)}>
        {active ? 'Deactivate' : 'Activate'}
      </button>

      <div className="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>
  );
}
```

**App.css**

```css
.demo {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px;
}

.toggle {
  align-self: flex-start;
  padding: 6px 16px;
  color: #111827;
  cursor: pointer;
  background: #f5f5f5;
  border: 1px solid #ccc;
  border-radius: 6px;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.tag {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  color: #374151;
  background: #e5e7eb;
  border-radius: 9999px;
  transition: all 0.2s ease;
}

.tag--active {
  color: white;
  background: #3b82f6;
}
```

## API Reference

`renderElement<State extends object, RenderedElementType extends Element, TagName extends keyof React.JSX.IntrinsicElements>(element, componentProps, params): ReactElement | null`

### Parameters

| Parameter | Type | Default |
| --- | --- | --- |
| `element` (required) | `TagName` | — |
| `componentProps` (required) | `{ className?: string \| ((state: State) => string \| undefined); style?: CSSProperties \| ((state: State) => CSSProperties \| undefined); render?: ReactElement \| ((props: HTMLProps, state: State) => ReactElement \| null) }` | — |
| `params` (required) | `{ state: State; ref?: Ref<RenderedElementType> \| Ref<RenderedElementType>[]; props?: object \| object[]; stateAttrMap?: { [Key in keyof State]?: string; } }` | — |

### Return Value

`ReactElement | null`

---

React documentation: https://videojs.org/docs/framework/react/llms.txt
All documentation: https://videojs.org/llms.txt
