Common props (<div>)

Accepts the shared prop surface every DOM element supports: className, style, id, refs and event handlers.

Signature
<div className="wrapper">Some content</div>

Parameters

ParameterTypeDescription
$childrenoptionalReactNodeAn element, string, number, portal, null/undefined/boolean, or an array of nodes. Usually written implicitly by nesting tags.
$dangerouslySetInnerHTMLoptional{ __html: string }Overrides the node's innerHTML with a raw HTML string. Unsanitised values are an XSS vector.
$refoptionalRefObject | ((node: Element | null) => void | (() => void))A ref object from useRef or createRef, or a ref callback. Filled with the DOM element for this node.
$suppressContentEditableWarningoptionalboolean= falseSuppresses the warning React shows for elements that have both children and contentEditable={true}.
$suppressHydrationWarningoptionalboolean= falseSilences server/client mismatch warnings for this element's attributes and content. Works one level deep only.
$styleoptionalobjectAn object of CSS styles with camelCase property names, e.g. { fontWeight: 'bold', margin: 20 }. Numbers get 'px' appended unless the property is unitless.
$classNameoptionalstringThe element's CSS class name. Preferred over style for anything not computed at runtime.
$idoptionalstringA unique identifier for the element. Generate it with useId to avoid clashes between instances.
$tabIndexoptionalnumberTab order for the element. -1 and 0 are the values worth using.
$hiddenoptionalboolean | stringWhether the element should be hidden.
$titleoptionalstringNative browser tooltip text for the element.
$roleoptionalstringThe element's accessibility role.
$htmlForoptionalstringFor <label> and <output>, associates the element with a form control. React uses the DOM property name rather than the HTML 'for' attribute.
$contentEditableoptionalbooleanLets the user edit the rendered element directly. React warns if you also pass React children.
$aria-*optionalstringARIA attributes, spelled exactly as in HTML (hyphenated, not camelCase).
$data-*optionalstringCustom data attributes, e.g. data-fruit="banana". Passing null or undefined removes the attribute.
$onClickoptional(e: SyntheticMouseEvent) => voidRepresentative of the whole event-handler family: every DOM event has an on* prop plus an on*Capture variant for the capture phase.

Return value

Renders the corresponding browser DOM node with the given attributes, listeners and children.

Errors

Passing both children and dangerouslySetInnerHTML to the same element throws.

Changelog

  • PHP 19.0.0ref is passed to function components as an ordinary prop, so forwardRef is no longer required to accept one.
  • PHP 19.0.0A ref callback may return a cleanup function; when it does, React calls the cleanup instead of re-invoking the callback with null.
  • PHP 19.0.0String refs were removed. Migrate to a ref object or a ref callback.

Every built-in browser component shares one prop surface. Whatever tag you write, you get className, style, id, tabIndex, role, all aria-* and data-* attributes, a ref, and roughly a hundred event handlers, each with a Capture twin that fires during the capture phase.

className or style

Reach for className whenever the values are known ahead of time — it is cheaper and cascades normally. Reach for style only for genuinely dynamic values (a computed width, a colour from data). Keys are camelCase, and a bare number becomes pixels: width: 100 renders width: 100px, while unitless properties like lineHeight or flexGrow are left alone.

Events are synthetic

Handlers receive a React event object, not the raw browser event. It normalises browser differences, so onBlur and onFocus bubble even though the native events do not, and onMouseLeave maps onto a native mouseout. If you need the original, read e.nativeEvent — but note that currentTarget and type on it may differ, because React attaches its listeners at the root.

What trips people up

ARIA attributes stay hyphenated (aria-label), but almost everything else uses the DOM property name: className, htmlFor, tabIndex. And children plus dangerouslySetInnerHTML on one element is a hard error, not a warning.

Example

Try it yourself
Loading editor…
Loading React…

When to use it

  • Wiring keyboard and pointer handlers onto a non-button element that has to act like a control
  • Applying a computed colour or width that cannot live in a CSS class
  • Grabbing the underlying DOM node with a ref to call focus() or measure it
  • Silencing an unavoidable server/client text mismatch on a single element

Frequently asked questions

Why doesn't my aria-label work when I write ariaLabel?

ARIA attributes are the one family React does not camel-case — write aria-label, aria-hidden and aria-describedby exactly as in HTML. Anything else is passed through as an unknown lowercase attribute, so ariaLabel lands in the DOM as arialabel and screen readers ignore it. The same applies to data-* attributes.

What is the difference between className and style in React?

className sets a CSS class and style sets inline CSS as a JavaScript object with camelCase keys. Use className for anything static — it is faster, cascades, and supports pseudo-classes and media queries, none of which inline styles can express. Reserve style for values computed at runtime, such as a bar width derived from data.

How do I get the real browser event instead of React's synthetic one?

Read e.nativeEvent inside the handler. React passes a synthetic event that normalises browser quirks, so onBlur bubbles and onMouseLeave is backed by a native mouseout. The mapping is not part of the public API, and properties such as currentTarget and type on the native event can differ from the React event because React listens at the root container.

More examples

Ref callbacks with cleanup

The ref callback returns a teardown function, so React disconnects the ResizeObserver when the node detaches instead of calling the callback again with null. Before React 19 you had to write the same callback defensively, checking for a null argument and disconnecting there. The paragraph shows the measured box dimensions, updating as you drag the resize handle.

Example · jsx
import { useState } from "react";

export default function ResizeReporter() {
  const [size, setSize] = useState(null);

  return (
    <div style={{ fontFamily: "system-ui, sans-serif", padding: 16 }}>
      <div
        ref={(node) => {
          if (!node) return;
          const observer = new ResizeObserver(([entry]) => {
            setSize({
              width: Math.round(entry.contentRect.width),
              height: Math.round(entry.contentRect.height)
            });
          });
          observer.observe(node);
          // React 19: returning a function makes it the cleanup.
          return () => observer.disconnect();
        }}
        style={{
          border: "1px dashed #94a3b8",
          padding: 24,
          resize: "both",
          overflow: "auto"
        }}
      >
        Drag my bottom-right corner.
      </div>
      <p>{size ? `${size.width} x ${size.height}` : "not measured yet"}</p>
    </div>
  );
}

Capture-phase handlers and event ordering

One click appends four entries in a fixed order: outer capture, button capture, button bubble, outer bubble. Capture handlers run outside-in before the event reaches the target, bubble handlers run inside-out after. This is the tool to reach for when a parent must veto or observe a click before a child's own handler sees it — call e.stopPropagation() inside the capture handler and the bubble entries never appear.

Example · jsx
import { useState } from "react";

export default function PhaseLog() {
  const [log, setLog] = useState([]);
  const push = (entry) => setLog((prev) => [...prev, entry]);

  return (
    <div style={{ fontFamily: "system-ui, sans-serif", padding: 16 }}>
      <div
        onClickCapture={() => push("outer capture")}
        onClick={() => push("outer bubble")}
        style={{ border: "1px solid #94a3b8", padding: 16 }}
      >
        <button
          type="button"
          onClickCapture={() => push("button capture")}
          onClick={() => push("button bubble")}
        >
          Click me
        </button>
      </div>
      <ol>
        {log.map((entry, i) => (
          <li key={i}>{entry}</li>
        ))}
      </ol>
      <button type="button" onClick={() => setLog([])}>Reset</button>
    </div>
  );
}

dangerouslySetInnerHTML with a sanitiser boundary

The stored markup is injected as real DOM, so the <strong> renders bold rather than appearing as literal angle brackets. Two rules the example encodes: the value must be an object with an __html key, and the element carrying it must have no children — adding any would throw. Everything inside is outside React's control, so events and refs on that subtree are yours to manage.

Example · jsx
// Renders trusted HTML only. `sanitize` stands in for a library such as DOMPurify.
function sanitize(html) {
  return html.replace(/<script[\s\S]*?<\/script>/gi, "");
}

function RichText({ html }) {
  return (
    <div
      className="prose"
      dangerouslySetInnerHTML={{ __html: sanitize(html) }}
    />
  );
}

export default function ArticleBody() {
  const stored = "<p>Shipped in <strong>19.0</strong>.</p>";
  return (
    <article style={{ fontFamily: "system-ui, sans-serif", padding: 16 }}>
      <h2>Release notes</h2>
      <RichText html={stored} />
    </article>
  );
}

Discussion

  • Be the first to comment on this lesson.