Extending PraxisJS
Build custom composables and decorators using the same primitives that power all built-in PraxisJS APIs.
Extending PraxisJS
PraxisJS exposes the same primitives used to build all first-party composables and decorators. When a built-in doesn't cover your use case, you can write your own — with full access to the signal engine and component lifecycle.
Creating Composables
Extend the Composable base class, implement setup() with signals and computeds, and use @Compose to attach it to any component. Covers constructor arguments, the getter() helper, and cleanup via onUnmount().
Creating Decorators
Builders for field, method, lifecycle method, getter, writable getter, getter observer and class decorators. The shared setup form creates a decorator's functions once per member, so building an instance costs almost nothing.
Choosing the right extension point
| You want to… | Use |
|---|---|
| Wrap a DOM API, external subscription, or event bus as a reusable reactive class | Composable → used via @Compose |
| Give a class field custom reactive get/set behavior | createFieldDecorator |
| Wrap a method with cross-cutting logic (logging, auth checks, analytics) | createMethodDecorator |
| Auto-subscribe/unsubscribe a method at mount/unmount | createLifecycleMethodDecorator |
| Transform or constrain a getter's return value | createGetterDecorator |
| Make a getter writable, with the decorator handling writes | createWritableGetterDecorator |
| Observe a getter for side effects without changing its value | createGetterObserverDecorator |
Augment the component lifecycle or wrap render() | createClassDecorator |
Builders take a setup behavior, run once per decorated member and shared by every instance, or a per-instance bind / wrap. Prefer setup and keep per-instance state in symbol slots on the instance. See Creating Decorators.
When to extend vs when to compose
If you find yourself writing the same onMount/onUnmount pattern across multiple components — subscribing to a DOM event, wrapping a browser API — that's a signal to extract a composable.
If you find yourself wrapping the same method logic (retry on failure, log every call, confirm before proceeding) — that's a signal to extract a method decorator.
See the examples on each page for concrete patterns you can adapt directly.
UI Libraries
Morphos and Kosmesis — the official UI ecosystem for PraxisJS. Headless primitives and copy-paste components built on the same signals and decorators as core.
Creating Composables
How to build custom composable classes in PraxisJS by extending Composable and using them with the @Compose decorator.