A React compatibility layer for Preact
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Reference system for accessing DOM nodes and component instances directly.
Creates ref objects for accessing DOM nodes and component instances.
/**
* Create a ref object for accessing DOM nodes or component instances
* @returns {RefObject} Ref object with current property
*/
function createRef();
/**
* Ref object interface
*/
interface RefObject<T> {
/**
* Current reference value (DOM node or component instance)
*/
current: T | null;
}Usage Examples:
import { createRef, Component } from 'preact-compat';
class InputComponent extends Component {
constructor(props) {
super(props);
this.inputRef = createRef();
}
focusInput = () => {
if (this.inputRef.current) {
this.inputRef.current.focus();
}
};
componentDidMount() {
// Access DOM node directly
console.log(this.inputRef.current); // <input> element
}
render() {
return (
<div>
<input ref={this.inputRef} type="text" />
<button onClick={this.focusInput}>Focus Input</button>
</div>
);
}
}Alternative ref pattern using callback functions.
/**
* Callback ref function
* @param {Element|Component|null} instance - DOM node or component instance
*/
type RefCallback<T> = (instance: T | null) => void;Usage Examples:
import { Component } from 'preact-compat';
class CallbackRefComponent extends Component {
inputElement = null;
setInputRef = (element) => {
this.inputElement = element;
};
focusInput = () => {
if (this.inputElement) {
this.inputElement.focus();
}
};
render() {
return (
<div>
<input ref={this.setInputRef} type="text" />
<button onClick={this.focusInput}>Focus Input</button>
</div>
);
}
}Pattern for passing refs through component boundaries.
import { createRef, cloneElement } from 'preact-compat';
// Higher-order component that forwards refs
function withForwardedRef(WrappedComponent) {
return function ForwardedRefComponent(props) {
const { forwardedRef, ...otherProps } = props;
return <WrappedComponent ref={forwardedRef} {...otherProps} />;
};
}
// Usage
class MyInput extends Component {
focus() {
this.inputRef.current.focus();
}
render() {
return <input ref={this.inputRef} {...this.props} />;
}
}
const ForwardedInput = withForwardedRef(MyInput);
class ParentComponent extends Component {
constructor(props) {
super(props);
this.childRef = createRef();
}
handleClick = () => {
this.childRef.current.focus();
};
render() {
return (
<div>
<ForwardedInput forwardedRef={this.childRef} />
<button onClick={this.handleClick}>Focus Child</button>
</div>
);
}
}Using refs in functional components (note: hooks not available in preact-compat 3.19.0).
import { createRef } from 'preact-compat';
// Ref passed as prop
function FunctionalInput({ inputRef, ...props }) {
return <input ref={inputRef} {...props} />;
}
// Usage
class ParentComponent extends Component {
constructor(props) {
super(props);
this.inputRef = createRef();
}
render() {
return (
<FunctionalInput
inputRef={this.inputRef}
placeholder="Type here..."
/>
);
}
}import { createRef, Component } from 'preact-compat';
class RefPatternsExample extends Component {
constructor(props) {
super(props);
// Multiple refs
this.formRef = createRef();
this.inputRefs = {
username: createRef(),
password: createRef(),
email: createRef()
};
// Dynamic refs array
this.itemRefs = [];
}
// Create refs for dynamic list
setItemRef = (index) => (element) => {
this.itemRefs[index] = element;
};
// Scroll to specific item
scrollToItem = (index) => {
if (this.itemRefs[index]) {
this.itemRefs[index].scrollIntoView({ behavior: 'smooth' });
}
};
// Form submission
handleSubmit = (e) => {
e.preventDefault();
const form = this.formRef.current;
const formData = new FormData(form);
// Validate inputs
Object.values(this.inputRefs).forEach(ref => {
if (ref.current && !ref.current.value) {
ref.current.focus();
return;
}
});
};
render() {
const items = ['Item 1', 'Item 2', 'Item 3'];
return (
<div>
<form ref={this.formRef} onSubmit={this.handleSubmit}>
<input
ref={this.inputRefs.username}
name="username"
placeholder="Username"
/>
<input
ref={this.inputRefs.password}
name="password"
type="password"
placeholder="Password"
/>
<input
ref={this.inputRefs.email}
name="email"
type="email"
placeholder="Email"
/>
<button type="submit">Submit</button>
</form>
{items.map((item, index) => (
<div
key={index}
ref={this.setItemRef(index)}
onClick={() => this.scrollToItem(index)}
>
{item}
</div>
))}
</div>
);
}
}interface RefObject<T> {
current: T | null;
}
type RefCallback<T> = (instance: T | null) => void;
type Ref<T> = RefCallback<T> | RefObject<T>;
// Common ref types
type DOMRef = Ref<HTMLElement>;
type InputRef = Ref<HTMLInputElement>;
type FormRef = Ref<HTMLFormElement>;
type ComponentRef<T extends Component> = Ref<T>;Install with Tessl CLI
npx tessl i tessl/npm-preact-compat