Creates a reactive value. Returns a getter/setter pair.
import { createSignal } from '@barefootjs/dom'
const [getter, setter] = createSignal<T>(initialValue: T)Type:
type Signal<T> = [
() => T, // getter
(valueOrFn: T | ((prev: T) => T)) => void // setter
]#Basic Usage
const [count, setCount] = createSignal(0)
// Read — call the getter
count() // 0
// Write — pass a value
setCount(5)
count() // 5
// Write — pass an updater function
setCount(n => n + 1)
count() // 6The getter is a function call — count(), not count. This is how the reactivity system tracks dependencies.
#Equality Check
The setter uses Object.is to compare the new value with the current value. If they are identical, no effects are triggered:
const [name, setName] = createSignal('Alice')
setName('Alice') // No effect runs — value unchangedFor objects and arrays, this means you need a new reference to trigger an update:
const [todos, setTodos] = createSignal([{ text: 'Buy milk' }])
// ❌ Mutating the same array — no update
const list = todos()
list.push({ text: 'Walk dog' })
setTodos(list) // Same reference, Object.is returns true
// ✅ New array — triggers update
setTodos([...todos(), { text: 'Walk dog' }])#With Effects
When a signal is read inside an effect, the effect automatically subscribes to changes:
const [count, setCount] = createSignal(0)
createEffect(() => {
console.log('Count is:', count()) // Runs whenever count changes
})
setCount(1) // Logs: "Count is: 1"
setCount(2) // Logs: "Count is: 2"#With JSX
In BarefootJS components, signal getters in JSX expressions create fine-grained DOM updates:
"use client"
import { createSignal } from '@barefootjs/dom'
export function Counter() {
const [count, setCount] = createSignal(0)
return (
<div>
<p>{count()}</p>
<button onClick={() => setCount(n => n + 1)}>+1</button>
</div>
)
}The compiler generates an effect that updates only the <p> text content when count changes — the rest of the DOM is untouched.
#Type Inference
The type parameter is inferred from the initial value:
const [count, setCount] = createSignal(0) // Signal<number>
const [name, setName] = createSignal('Alice') // Signal<string>
const [visible, setVisible] = createSignal(false) // Signal<boolean>For union types or complex types, specify the type parameter:
const [user, setUser] = createSignal<User | null>(null)
const [filter, setFilter] = createSignal<'all' | 'active' | 'done'>('all')