Skip to content

Instantly share code, notes, and snippets.

@marvinhagemeister
Last active October 6, 2024 20:13
Show Gist options
  • Save marvinhagemeister/daada86f82466dff81d48840c8d5f27b to your computer and use it in GitHub Desktop.
Save marvinhagemeister/daada86f82466dff81d48840c8d5f27b to your computer and use it in GitHub Desktop.
Preact Signals `bind:value`
import { options } from "preact";
import { Signal } from "@preact/signals";
// Add `bind:value` to JSX types
declare global {
namespace preact.createElement.JSX {
interface HTMLAttributes {
"bind:value"?: Signal<string | string[] | number | undefined>;
}
}
}
function isSignal(x: any): x is Signal {
return (
x !== null &&
typeof x === "object" &&
typeof x.peek === "function" &&
"value" in x
);
}
let oldVNodeHook = options.vnode;
options.vnode = (vnode: VNode<any>) => {
const { type, props } = vnode;
if (
typeof type === "string" &&
props &&
props["bind:value"] &&
isSignal(props["bind:value"])
) {
const signal = props["bind:value"];
props.value = signal;
let oldOnInput = props.onInput;
props.onInput = (event: any) => {
signal.value = event.target.value;
if (oldOnInput) oldOnInput(event);
};
}
if (oldVNodeHook) oldVNodeHook(vnode);
};
import { render, VNode } from "preact";
import { useSignal } from "@preact/signals";
import "./bind-plugin"; // just needs to be imported once in the code base, best to do at the top
function App() {
const signal = useSignal("");
return (
<div>
<h1>Preact signal bind demo</h1>
<label for="input">Some text&nbsp;</label>
<input id="input" bind:value={signal} placeholder="type something" />
<p>Input value: {JSON.stringify(signal.value)}</p>
</div>
);
}
render(<App />, document.getElementById("app")!);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment