Skip to content

Components

A Sygnal component is a function with optional static properties attached to it. At minimum, a component is just a function that returns JSX:

function MyComponent() {
return <div>Hello World</div>
}

To make a component interactive, attach .initialState, .intent, and .model properties:

function Counter({ state }) {
return <div>Count: {state.count}</div>
}
Counter.initialState = { count: 0 }
Counter.intent = ({ DOM }) => ({
INCREMENT: DOM.select('.btn').events('click')
})
Counter.model = {
INCREMENT: (state) => ({ count: state.count + 1 })
}
PropertyTypeDescription
.initialStateObjectThe starting state for the component
.intentFunctionMaps driver sources to named action streams
.modelObjectDefines what happens for each action
.calculatedObjectDerived state fields computed from base state
.contextObjectValues passed down to all descendants
.peersObjectSibling components that share the same sources
.componentsObjectNamed child components
.onErrorFunctionError boundary handler — receives (error, { componentName }), returns fallback VNode
.isolatedStateBooleanRequired when a sub-component has .initialState (prevents accidental parent state overwrite)
.storeCalculatedInStateBooleanWhether calculated fields are stored in state (default: true)
.debugBooleanEnable debug logging for this component
.DOMSourceNameStringCustom name for the DOM driver (default: 'DOM')
.stateSourceNameStringCustom name for the state driver (default: 'STATE')

The component function is the view. It receives a single object where props from the parent are spread at the top level alongside state, children, and context:

function MyComponent({ state, className, children, context, ...peers }) {
return (
<div className={className}>
<h1>{state.title}</h1>
{children}
</div>
)
}
ParameterDescription
stateThe current component state
childrenChild elements passed between the component’s opening and closing tags
contextValues from ancestor components’ .context definitions
Named peersAny peer components defined in .peers are available by name
Individual propsProps from the parent (e.g., title, className) are spread at the top level

Props are not nested under a props key. If a parent renders <MyChild title="Hello" />, the child destructures title directly: function MyChild({ title, state }) { ... }.

The view function must be pure: it should only use the values it receives to produce virtual DOM. Never perform side effects (API calls, direct DOM manipulation, etc.) inside the view.

The view function also receives state as a second positional argument, which can be convenient:

const MyComponent = (_props, state) => {
return <div>{state.count}</div>
}