Skip to main content
Creates a mutable ref object that can hold a reference to a DOM node or component instance.

Signature

function createRef<T = any>(): RefObject<T>

Type Parameters

T
any
default:"any"
The type of the value the ref will hold (e.g., HTMLDivElement, HTMLInputElement).

Return Value

Returns a RefObject<T> with the following structure:
interface RefObject<T> {
  current: T | null;
}
The current property:
  • Initially set to null
  • Updated by Preact when the component mounts
  • Set to the DOM node or component instance
  • Reset to null when the component unmounts

Description

createRef creates a mutable object whose current property is initialized to null. This object persists for the lifetime of the component and is used to access DOM nodes or component instances directly. Refs are useful for:
  • Managing focus, text selection, or media playback
  • Triggering imperative animations
  • Integrating with third-party DOM libraries
  • Accessing component methods

Implementation

The function is implemented in src/create-element.js:73:
export function createRef() {
  return { current: NULL };
}
The implementation is simple - it returns a plain object with a current property initialized to null.

Usage Examples

Accessing DOM Elements

import { createRef, Component } from 'preact';

class AutoFocusInput extends Component {
  inputRef = createRef();
  
  componentDidMount() {
    // Focus the input after mount
    this.inputRef.current.focus();
  }
  
  render() {
    return <input ref={this.inputRef} type="text" />;
  }
}

With Function Components

import { createRef } from 'preact';
import { useEffect } from 'preact/hooks';

function VideoPlayer() {
  const videoRef = createRef();
  
  useEffect(() => {
    // Play video on mount
    videoRef.current.play();
  }, []);
  
  const handlePause = () => {
    videoRef.current.pause();
  };
  
  return (
    <div>
      <video ref={videoRef} src="video.mp4" />
      <button onClick={handlePause}>Pause</button>
    </div>
  );
}

Measuring DOM Elements

import { createRef, Component } from 'preact';

class MeasureDiv extends Component {
  divRef = createRef();
  
  measureElement = () => {
    const element = this.divRef.current;
    console.log('Width:', element.offsetWidth);
    console.log('Height:', element.offsetHeight);
    console.log('Position:', element.getBoundingClientRect());
  }
  
  render() {
    return (
      <div>
        <div ref={this.divRef} style={{ width: '200px', height: '100px' }}>
          Measure me!
        </div>
        <button onClick={this.measureElement}>Get Measurements</button>
      </div>
    );
  }
}

Managing Focus

import { createRef, Component } from 'preact';

class Form extends Component {
  nameRef = createRef();
  emailRef = createRef();
  
  handleNameSubmit = (e) => {
    e.preventDefault();
    // Move focus to email field
    this.emailRef.current.focus();
  }
  
  render() {
    return (
      <form>
        <input
          ref={this.nameRef}
          placeholder="Name"
          onKeyPress={(e) => e.key === 'Enter' && this.handleNameSubmit(e)}
        />
        <input
          ref={this.emailRef}
          type="email"
          placeholder="Email"
        />
      </form>
    );
  }
}

With TypeScript

import { createRef, Component } from 'preact';

class TypedInput extends Component {
  // Specify the element type
  inputRef = createRef<HTMLInputElement>();
  buttonRef = createRef<HTMLButtonElement>();
  
  componentDidMount() {
    // TypeScript knows inputRef.current is HTMLInputElement | null
    this.inputRef.current?.focus();
    
    // Access type-specific properties
    const value = this.inputRef.current?.value;
    const isDisabled = this.buttonRef.current?.disabled;
  }
  
  render() {
    return (
      <div>
        <input ref={this.inputRef} />
        <button ref={this.buttonRef}>Submit</button>
      </div>
    );
  }
}

Text Selection

import { createRef, Component } from 'preact';

class SelectableText extends Component {
  textRef = createRef();
  
  selectAll = () => {
    const input = this.textRef.current;
    input.select();
  }
  
  selectRange = (start, end) => {
    const input = this.textRef.current;
    input.setSelectionRange(start, end);
    input.focus();
  }
  
  render() {
    return (
      <div>
        <input
          ref={this.textRef}
          type="text"
          defaultValue="Select this text"
        />
        <button onClick={this.selectAll}>Select All</button>
        <button onClick={() => this.selectRange(0, 6)}>Select First Word</button>
      </div>
    );
  }
}

Integrating Third-Party Libraries

import { createRef, Component } from 'preact';
import * as d3 from 'd3';

class D3Chart extends Component {
  svgRef = createRef();
  
  componentDidMount() {
    // Use D3 with the DOM element
    const svg = d3.select(this.svgRef.current);
    svg.append('circle')
      .attr('cx', 50)
      .attr('cy', 50)
      .attr('r', 40)
      .attr('fill', 'blue');
  }
  
  render() {
    return <svg ref={this.svgRef} width="100" height="100" />;
  }
}

Multiple Refs

import { createRef, Component } from 'preact';

class MultipleRefs extends Component {
  firstRef = createRef();
  secondRef = createRef();
  thirdRef = createRef();
  
  focusNext = (currentRef, nextRef) => {
    const current = currentRef.current;
    if (current.value.length >= current.maxLength) {
      nextRef.current.focus();
    }
  }
  
  render() {
    return (
      <div>
        <input
          ref={this.firstRef}
          maxLength={3}
          onChange={() => this.focusNext(this.firstRef, this.secondRef)}
        />
        <input
          ref={this.secondRef}
          maxLength={3}
          onChange={() => this.focusNext(this.secondRef, this.thirdRef)}
        />
        <input ref={this.thirdRef} maxLength={3} />
      </div>
    );
  }
}

Forwarding Refs

import { createRef, forwardRef } from 'preact';

// Component that forwards its ref to an internal element
const FancyInput = forwardRef((props, ref) => (
  <div className="fancy-input">
    <input ref={ref} {...props} />
  </div>
));

function Parent() {
  const inputRef = createRef();
  
  const focusInput = () => {
    inputRef.current.focus();
  };
  
  return (
    <div>
      <FancyInput ref={inputRef} placeholder="Forwarded ref" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

Ref vs useRef Hook

For function components, prefer the useRef hook:
// Class component - use createRef
import { createRef, Component } from 'preact';

class MyClass extends Component {
  myRef = createRef();
  
  render() {
    return <div ref={this.myRef} />;
  }
}

// Function component - use useRef
import { useRef } from 'preact/hooks';

function MyFunction() {
  const myRef = useRef(null);
  
  return <div ref={myRef} />;
}
Key differences:
  • createRef creates a new object every time
  • useRef persists the same object across re-renders
  • useRef is preferred for function components

Common Patterns

Conditional Refs

import { createRef, Component } from 'preact';

class ConditionalRef extends Component {
  inputRef = createRef();
  
  componentDidUpdate(prevProps) {
    if (this.props.shouldFocus && !prevProps.shouldFocus) {
      this.inputRef.current?.focus();
    }
  }
  
  render() {
    return (
      <input
        ref={this.inputRef}
        type="text"
        placeholder="Type here"
      />
    );
  }
}

Callback Refs

For more control, use callback refs instead:
import { Component } from 'preact';

class CallbackRefExample extends Component {
  setInputRef = (element) => {
    this.inputElement = element;
    if (element) {
      element.focus();
    }
  }
  
  render() {
    return <input ref={this.setInputRef} />;
  }
}

Best Practices

  1. Check for null: Always check if ref.current exists before using it
if (this.myRef.current) {
  this.myRef.current.focus();
}

// Or use optional chaining
this.myRef.current?.focus();
  1. Don’t overuse refs: Use refs only when necessary. For most cases, data flow through props is preferred
  2. Avoid string refs: Preact supports string refs for compatibility, but object refs are preferred
// ❌ Avoid string refs
<input ref="myInput" />

// ✅ Use object refs
<input ref={this.myRef} />
  1. Function components: Use useRef hook instead of createRef in function components
  • useRef hook - Ref hook for function components
  • forwardRef - Forward refs through components
  • Component - Class component API
  • h - Create elements with refs

Build docs developers (and LLMs) love