DOM Refs
Refs let you capture the DOM node behind an element. Ripple uses the normal JSX attribute shape:
| Syntax | Use it for |
|---|---|
ref={value} | One ref for the current element or component. |
ref={[a, b]} | Multiple refs for the same element. |
Ref values can be callbacks, Tracked values from track(), or mutable identifiers/member expressions. Mutable refs are assigned when the element mounts and cleared when it unmounts.
import { track } from 'ripple';
export default function App() {
let div: HTMLDivElement | undefined;
const input = track<HTMLInputElement | null>(null);
const state: { button?: HTMLButtonElement } = {};
return <>
<div ref={div}>"Hello world"</div>
<input ref={input} type="text" />
<button ref={state.button}>"Save"</button>
</>;
}Callback Refs
Callback refs receive the DOM node when the element mounts. Return a cleanup function to run when the element is removed.
export function App() {
function setup(node: HTMLDivElement) {
console.log('mounted', node);
return () => {
console.log('unmounted', node);
};
}
return <div ref={setup}>"Hello world"</div>
}You can also create callback refs inline.
export function App() {
let div: HTMLDivElement | undefined;
return <div
ref={(node) => {
div = node;
console.log('mounted', node);
return () => {
div = undefined;
};
}}
>
"Hello world"
</div>
}Function factories work well when a library returns the ref callback for you, or when the ref setup needs configuration.
import { fadeIn } from 'some-library';
export function App({ ms }) {
return <div ref={fadeIn({ ms })}>"Hello world"</div>
}Multiple Refs
Use an array when one DOM element needs more than one ref.
import { track } from 'ripple';
export function App() {
let input: HTMLInputElement | undefined;
const trackedInput = track<HTMLInputElement | null>(null);
return <input ref={[input, trackedInput, (node) => console.log(node)]} />
}Component Forwarding
Components receive ref={...} as a prop. Forward it explicitly or include it in a spread onto the host element that should be exposed.
function Input({ id, ...rest }) {
return <input {id} {...rest} />
}
export function App() {
let input: HTMLInputElement | undefined;
return <Input id="email" ref={input} />
}Named props such as inputRef are ordinary component API props. Pass them into ref={...} inside the receiving component when you want to forward them.
export function Field({ inputRef, ...rest }) {
return <label>
"Search"<input type="search" ref={inputRef} {...rest} />
</label>
}
export function App() {
let input: HTMLInputElement | undefined;
return <Field inputRef={input} placeholder="Search docs" />
}createRefKey
createRefKey() creates a unique object key that Ripple recognizes as a ref when the object is spread onto an element. This is useful when refs need to be assembled programmatically.
import { createRefKey, track } from 'ripple';
export function App() {
let &[value] = track('');
let input: HTMLInputElement | undefined;
const props = {
id: 'example',
value,
[createRefKey()]: (node: HTMLInputElement) => {
input = node;
const onInput = () => {
value = node.value;
console.log(value);
};
node.addEventListener('input', onInput);
return () => {
input = undefined;
node.removeEventListener('input', onInput);
};
},
};
return <>
<input type="text" {...props} />
<Input {...props} />
</>;
}
function Input({ id, value, ...rest }) {
return <input type="text" {id} {value} {...rest} />
}