We’ve migrated our documentation to a new site, which means some URLs have changed. If you hit a broken link, submit a support ticket.
Subscriptions
English French
English French

What is ref and how do I use it?

LIGHTWEIGHT TEMPLATES

It is a plain assignment: when the element is created, the compiler assigns the DOM node itself to x. So x holds an HTMLInputElement, and you read .value, .checked or call .focus() on it directly.

JS tab

let emailInput;
let acceptsTerms;

JSX tab

<input type="email" ref={emailInput} required />
<input type="checkbox" ref={acceptsTerms} />
<PianoPrimaryButton
  onClick={() => submit()}
  externalEventName="signup"
  externalEventParams={{
    email: emailInput?.value,
    accepted: acceptsTerms?.checked,
  }}
>
  <T>Sign up</T>
</PianoPrimaryButton>

Three rules make the difference between this working and failing silently:

  • Declare it with let at the top level of the JS tab. See the previous question.

  • It is empty until the element is mounted. Reading emailInput.value while the JS tab runs — or inside a createEffect that fires before mount — throws. Read it from an event handler, from onMount, or from a prop that is evaluated on interaction.

  • Use optional chaining. emailInput?.value. If the element sits inside a <Show> that has not rendered, the variable is still undefined, and a throw inside a click handler loses the click's side effects without any visible error.

Ref or a signal? Pick ref when the value is only ever read at interaction time; you get the live DOM value for free, with no wiring. Pick a signal when the value also drives rendering: a character counter, a conditional block, a computed label. A ref holds an element, not reactive state, so nothing re-renders when its contents change.

// JS tab — a signal, because the length is rendered as well as read
const [subject, setSubject] = createSignal("");
<input type="text" maxlength="60" onInput={(e) => setSubject(e.currentTarget.value)} />
<p>{subject().length} / 60</p>

A full worked example using both in one form: Lightweight templates external events, Example 2.

Last updated: