Special Attributes
Some attributes have behavior specific to Retend elements. The most common are class, style, and ref.
The class Attribute
To specify CSS classes on an element, use the class attribute (unlike React, which uses className). You can pass a string of space-separated classes, exactly as you would in standard HTML.
<div class="card p-4 shadow">Content goes here</div>
Dynamic Classes
Use arrays and objects to define classes conditionally. This avoids constructing class strings manually.
You can pass an array of strings, or objects where the key is the class name and the value is a boolean or a Cell. When a value is a Cell, Retend binds the class to that Cell and updates the class without rerendering the component.
import { Cell } from 'retend'; export function ToggleButton() { const isActive = Cell.source(false); const isInactive = Cell.derived(() => !isActive.get()); return ( <button class={[ 'btn', { 'btn-active': isActive, 'btn-inactive': isInactive, }, ]} onClick={() => isActive.set(!isActive.get())} > Toggle me </button> ); }
The style Attribute
The style attribute accepts either a standard CSS string or an object containing your styles.
When using an object, CSS property names should typically be written in camelCase (e.g., backgroundColor instead of background-color).
<div style={{ color: 'var(--color-brand)', borderRadius: '8px' }}> Styled content </div>
As with class, style object values can be Cells. Retend updates the affected style when the Cell changes without rerendering the element.
The ref Attribute
The ref attribute provides a reference to the underlying UI element after it is created. Use it for imperative actions, focus management, or integration with non-reactive third-party libraries.
Create a ref with Cell.source(null) and pass the cell to the ref attribute. Retend sets the cell to the element after it is created.
import { Cell } from 'retend'; export function AutoFocusInput() { // 1. Create a reference starting at null const inputRef = Cell.source(null); const handleFocus = () => { // 3. Access the element safely using .get() inputRef.get()?.focus(); }; return ( <div class="flex gap-2"> <input ref={inputRef} // 2. Attach the reference type="text" placeholder="Type here..." /> <button onClick={handleFocus}>Focus the input</button> </div> ); }
Example: Media Control
Use refs to interact with browser APIs that Retend does not wrap reactively, such as APIs for controlling <video> or <audio> elements.
import { Cell } from 'retend'; export function VideoPlayer() { const videoRef = Cell.source<HTMLVideoElement | null>(null); const togglePlay = () => { const video = videoRef.get(); if (video) { if (video.paused) video.play(); else video.pause(); } }; return ( <div class="video-container"> <video ref={videoRef} src="/promo.mp4" /> <button onClick={togglePlay}>Play/Pause</button> </div> ); }
Ref Forwarding
ref={cell} is a prop. Pass it to a child component and attach it to an element in that component.
import { Cell, onSetup } from 'retend'; function MyInput(props) { return <input ref={props.ref} class="custom-input" />; } export function ParentComponent() { const inputRef = Cell.source(null); onSetup(() => { inputRef.get()?.focus(); }); return <MyInput ref={inputRef} />; }
Fragment refs
A Fragment ref stores the nodes that a Fragment renders. Use a Fragment ref when you need to inspect or process multiple nodes without adding a wrapper element.
To create a Fragment ref:
- Create a source cell with an initial value of
null. - Pass the cell to the Fragment's
refattribute. - Read the rendered nodes with the cell's
get()method.
import { Cell, Fragment } from 'retend'; export function MessageGroup() { const nodesRef = Cell.source<Node[] | null>(null); const logNodes = () => { console.log(nodesRef.get()); }; return ( <> <Fragment ref={nodesRef}> <p>First message</p> <p>Second message</p> </Fragment> <button onClick={logNodes}>Log messages</button> </> ); }
Retend updates the ref cell whenever the Fragment's rendered content changes. The cell contains:
- Each rendered element and text node, in document order.
- An empty array when the Fragment renders no nodes.
For example, the following ref changes when showSuccess changes:
import { Cell, Fragment, If } from 'retend'; export function StatusMessage() { const showSuccess = Cell.source(true); const nodesRef = Cell.source<Node[] | null>(null); return ( <> <Fragment ref={nodesRef}> {If( showSuccess, () => ( <p>Saved</p> ), () => ( <p>Save failed</p> ) )} </Fragment> <button onClick={() => showSuccess.set(!showSuccess.get())}> Toggle status </button> </> ); }
Use an element ref when you need one specific element instead of the complete Fragment output.