Bonds

State without prop drilling.

A Bond is a class-based state container that lives in Svelte context. Root components create one; every descendant reads it automatically — no props passed between them.

What are Bonds?

A two-part architecture: BondState holds reactive data, Bond manages elements and context.

A Bond is split into two classes. BondState owns the reactive props and mutation methods — it's where your component's logic lives. Bond owns the DOM element references (via BondAtom subclasses), generates element spreads with ARIA and event handlers, and puts itself into Svelte context via .share().

Child components call Bond.get() to retrieve the bond from context and read state, call methods, or access captured DOM elements — without any props being threaded between components.

Key features

What Bonds give you that plain stores and prop-drilling don't.

Separation of concerns

BondState owns logic; Bond owns DOM. Neither knows about Svelte component lifecycle.

Automatic element capture

BondAtom attachments track DOM nodes the moment they mount — no manual ref management needed.

Full type safety

Generic typing from props → state → elements → spread. Your IDE knows every method at authoring time.

Fine-grained reactivity

Props are passed as a function — only the properties actually read inside the Bond trigger updates.

Context integration

Built-in .share(), .get(), .set() — share state across any component tree depth.

Customisable via factory

Components accept a factory prop so callers can swap in Bond subclasses for testing or extension.

Creating a Bond

Four pieces: props type, BondState class, BondAtom subclasses, and Bond class.

1 — Define state props and BondState

2 — Create BondAtom subclasses and Bond

Each BondAtom subclass represents one DOM element. Override attrs for ARIA/data attributes and handlers for events. Element capture is automatic — BondAtom.attachments wires up the element reference when the node mounts.

Using Bonds in components

Root components create and share the Bond; children retrieve it from context.

Root component

Call .share() to place the Bond in Svelte context, then spread .spread on each element — it contains attrs, event handlers, and the attachment that captures the DOM node.

Child component

Children call the static .get() to retrieve the Bond. Use bond.element('key') to access captured DOM elements.

Factory prop

Expose a factory prop so callers can inject a custom Bond subclass — useful for testing or extending behavior.

Accessing from a parent

Export a getBond() function from the root component so parent components can imperatively read or mutate bond state.

Architecture deep dive

BondState props, reactive derived values, and context sharing.

BondState — props and logic

this.props calls the function passed to the constructor, returning the live reactive object built by defineState. Use $derived as a class field for computed values — Svelte 5 Runes work inside class bodies.

Reactive props with defineState

defineProperty creates a reactive getter/setter pair on the props object. When BondState accesses this.props.open, it runs the getter — and only that getter triggers updates, giving fine-grained reactivity.

Context sharing

.share() wraps setContext. The static .get() wraps getContext. Every Bond subclass defines its own unique context key.

When to use Bonds

Bonds are powerful but not always the right tool.

Compound components

Multiple sibling parts (trigger, content, item) that must share state — the primary use case for Bonds.

DOM coordination

When parts need to measure, focus, or position relative to each other — BondAtom element refs make this clean.

Reusable logic

Extract component behavior into a plain class — easy to unit-test without mounting a component.

Extensibility

Subclass a Bond to override ARIA attrs or add behavior without forking the original component.

When not to use Bonds

For a single piece of state inside one component, a plain $state variable is simpler and clearer. Don't reach for the Bond pattern until you have multiple coordinating parts.

Best practices

Guidelines for working effectively with Bonds.

01

Wrap props with defineState

Pass a function to BondState — not a plain object. defineProperty bridges $bindable props into the Bond without losing reactivity.

02

Spread .spread on elements

Always use {...bond.root().spread} — it includes attrs, handlers, and the attachment that captures the element reference.

03

Use unique CONTEXT_KEY values

Prefix with your package or app name: '@my-app/bond/accordion'. When subclassing an existing Bond, keep the parent key to preserve context compatibility.

04

Export getBond()

Export a getBond() function from root components so parents can access the bond imperatively when needed.

05

Name your Bond in the constructor

Pass a name string to super(state, 'my-component') — it becomes the data-bond attribute used for debugging and CSS selectors.

Learn more

See Bonds in action or understand the architecture behind them.

© 2026 Svelte Atoms. Open source under the MIT license.

Built with Svelte 5 · Runes · TailwindCSS