SpyneJS

STAGE: ViewStream

  • Defines HTML elements and content

  • Appends to DOM or nests ViewStream instances

  • Built in el$ Selector

  • Encapsulated and communicates with all Channels

  • Imports native methods from SpyneTraits

ViewStream

Dynamically generates the DOM by nesting ViewStream instances.

ViewStreamnew Instance

CONSTRUCTORnew ViewStream (

propsObject={}

)

Parameter

Default

Type(s)

Description

props

{}

Object

Contains all properties for the instance.

└─tagName

"div"

String

The tag name of the HTML root element.

└─[Attributes]

HTML Attributes

HTML attributes (id, class, dataset, etc.) applied to the root element. Click here for a complete list of attributes.

└─template

undefined

HTML Template
HTML String

The HTML markup for rendering dynamic content. See DomElementTemplate for syntax.

String Literal

Renders HTML content using String Literals

└─data

undefined

Object | Array | String

Data used for placeholder replacement in template. If a string is provided, it becomes text content.

└─traits

[]

SpyneTrait Class

An array of SpyneTrait classes. Each trait's methods are bound to the ViewStream instance, adding custom logic or behaviors.

└─channels

[]

String | Array

One or more channel names. Each entry is either "CHANNEL_NAME" or [CHANNEL_NAME, true], the boolean skips the replayed first payload (typically needed when the Channel's replay event triggers the rendering of the current ViewStream instance). See .addActionListeners for more info.

└─el

undefined

HTML Element / DOM Element

Usually defined by tagName, but can be added as an existing DOM element.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

Creates a new ViewStream instance responsible for rendering and managing a DOM element, using the provided configuration (props).

The constructor declaratively sets up:

  • tagName + Attributes: Defines the root DOM element for the ViewStream. In most cases, a new element is created; providing an existing el is an optional edge case.
  • template + data: Generate the view's HTML markup or text content dynamically.
  • traits: Attach reusable logic methods to the ViewStream instance — cleanly separating functionality from structure.
  • channels: Integrate behavior streams by listening to or broadcasting through named Channels.

The constructor shows how ViewStreams declaratively wire structure, content, and behavior — forming modular, scalable building blocks inside a SpyneJS application.

    import { ViewStream } from 'spyne';
    
    // Simple "Hello World" view
    const myView = new ViewStream({
      data: 'Hello World'
    });
    
    // Insert into DOM
    myView.appendToDom(document.body);
           
    

STAGE: DomElement

  • DomElement is used to create ViewStreams HTML element and its content

  • Can be used to create HTML elements that do not require integration with Channels and SpyneTraits

DomElement

Creates a DOM element and populates it with HTML or text content, using the same underlying logic as a ViewStream.

DomElementNew Instance

CONSTRUCTORnew DomElement (

props: Object={}

)

Parameter

Default

Type(s)

Description

props  

{}

Object

Contains all of the properties used to define the element.

└─tagName

div

String

props.tagName

└─[Attributes]

undefined

[ class , dataset ] etc.

[ class , dataset ] etc.

└─template

undefined

HTML | String | String Literal

HTML | String | String Literal

└─data

undefined

Object | Array | String

Object | Array | String

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

DomElement is used for basic HTML and text content generation using ViewStream's constructor interface.

Behavior

  • Generates a top-level DOM element based on tagName and [Attributes].
  • Renders HTML or text content via template and data.
  • Excludes channel or trait functionality; use ViewStream if additional reactive features are needed.

  // Define the data
    const data = "Hello World";
    // Create the DomElement
    const html = new DomElement({data});
  // Append to body
    document.body.appendChild(html.render());
    
    

STAGE: DomElementTemplate

  • This generates HTML from templates and data.

  • Fastest way to generate large amounts of DOM Content without any logic or code

  • Can be rendered as an HTML String or DocumentFragement

DomElementTemplate

A flexible system for generating HTML content using Templates and Data—primarily used for rendering HTML within ViewStreams and DomElements.

DomElementTemplateNew Instance

CONSTRUCTORnew DomElementTemplate (

templateHTML Template | String data Object | Array | String

)

Parameter

Default

Type(s)

Description

template

undefined

HTML | String | String Literal

A mustache-style template containing {{variable}} placeholders. Placeholders are replaced by corresponding values from the data argument.

data

undefined

Object | Array | String

The values used to populate placeholders. Most commonly an object whose keys match the placeholder names. Arrays at the root work with the bare-array shorthand syntax. A primitive string passes through unchanged.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

DomElementTemplate is SpyneJS's template engine. It takes a template string with mustache-style placeholders and a data object, and produces either an HTML string or a DocumentFragment ready to mount into the DOM.

Templates support variable interpolation, dot-notation property access, array iteration, object sections as conditional wrappers, and one level of nested array iteration. Logic is intentionally not supported — no if/else, no computed expressions, no custom helpers. Decisions and data shaping happen in SpyneTrait methods, not in the template.

Security — Sanitized by Default

Template HTML and interpolated values are sanitized by default; no configuration is required. Bracket count is not significant — {{key}} and {{{key}}} behave identically, because protection doesn't depend on template syntax.

The security posture is decided once per application, in SpyneApp.init: mode selects the sanitization posture (app for production, richtext for CMS and authoring tools), and pairing it with strict: true — the recommended production posture — adds Trusted Types enforcement at the DOM-sink layer. See Security Configuration under SpyneApp for the full set of options.

What's Not Supported (and What to Use Instead)

Templates are data files, not code. A SpyneJS template is a declarative description of how data maps to DOM — it does not contain logic, decisions, or computation. SpyneJS enforces this by design: the engine has no syntax for it. The constructs below appear in other template engines but are deliberately omitted here, because every one of them belongs in a SpyneTrait or a ChannelPayloadFilter where logic lives. Each has an idiomatic replacement:

Inverted sections ({{^key}}) — shape the data so the section you want renders naturally, or emit a placeholder from a SpyneTrait.

If/else and conditional expressions — use object-section-as-conditional, or resolve the condition in a SpyneTrait and expose a resolved object.

Computed expressions and arithmetic — pre-compute in a SpyneTrait. The auto-injected {{loopNum}} handles 1-based indexing.

Custom helpers and filters — derived values are computed in SpyneTraits before reaching the template.

Partials and includes — composition happens at the ViewStream level. Nested ViewStream instances are SpyneJS's mechanism for reusable UI fragments, with lifecycle semantics built in.

Dynamic tag names (e.g. ) — use the flag-conditional pattern. Pre-compute a flag (e.g., ) and use object sections to emit the appropriate tag.

Deeper than one-level nesting — restructure into nested ViewStream instances.

  // Define the template
  const template = "<p>{{text}}</p>";  
  // Define the data
  const data = {text: "Hello World"};
  // Render using DomElementTemplate
  const html = new DomElementTemplate(
      template, data
      ).renderDocFrag();
  // Append to body
    document.body.appendChild(html);
    
    

STAGE: Channel

  • Unified system to transmit all types of events and data

  • Combines and parses data from other channels

  • Create advanced observables using rxjs library

Channel

Channels provide a unified interface to manage and synchronize application behavior, including user interactions, browser activities, and data fetching.

ChannelNew Instance

CONSTRUCTORnew Channel (

channelNameString=undefinedpropsObject={}

)

Parameter

Default

Type(s)

Description

channelName

(required)

String

A unique identifier used by ViewStream and custom Channel instances for accessing the Channel via getChannel.

props

{}

Object

Holds all of the properties for the Channel instance.

└─replay

false

Boolean

Determines if the Channel "replays" the last payload for new subscribers.

└─traits

[]

Array

List of SpyneTrait instances; their methods become local methods of the Channel.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

The constructor initializes a new Channel instance and sets up a dedicated RxJS Subject, accessible via the instance's obs$ property.

replay Property:
This is an important behavioral feature, and determines if new subscribers receive the last, 'cached' ChannelPayload (also determines if obs$ is an RxJS Subject or a ReplaySubject).

What it Does:

  • Emits: Persistent streams of observable data known as ChannelPayloads.
  • Merges and Subscribes to: Multiple channel data streams for precise synchronization of UX and application behaviors.
  • Registers: Actions specifically designed to connect ("wire") payloads to local methods.
  • Extends: RxJS Subjects, providing access to the full RxJS library for creating custom observables and advanced stream management.

ChannelPayloads are emitted when:

  • Filtered events from subscribed-to channels trigger actions.
  • Typically used for edge cases and third-party libraries, local Channel methods can be called from a ViewStream's sendInfoToChannel method.
  • The local obs$ instance is extended via the RxJS library.

ViewStream and Event Integration:

  • Events: Captures events emitted by the three Event Channels.
  • ViewStream Information: Receives observable data from ViewStream's sendInfoToChannel method.

SpyneTrait Integration:

  • Adds Logic: By binding pure functions from SpyneTraits as local methods.

    
    const myChannel = new MyChannel("CHANNEL_MY_CHANNEL");
    spyneApp.registerChannel(myChannel);
    
    

STAGE: ChannelPayload

  • This data interface for all channels

  • Provides consistent, immutable data

ChannelPayload

This provides a consistent interface to efficiently deliver behavior content.

ChannelPayloadNew Instance

CONSTRUCTORnew ChannelPayload (

channelNameString=undefinedactionString=undefinedpayloadObject=undefinedsrcElementObject=undefinedeventUIEvent=undefined

)

Parameter

Default

Type(s)

Description

channelName

(required)

String

Name of the channel emitting the payload.

action

(required)

String

Action label used to filter and route logic.

payload

(required)

Object

Custom data (or user event dataset if broadcast from ViewStream).

srcElement

{}

Object

Reference to the DOM element that triggered the event (if applicable).

event

{}

UIEvent

Native event object from the browser (e.g., click, input).

Return Parameter(s)

Default

Type(s)

Description

{

immutable Object Frozen Object.

}

constructor

ChannelPayload provides a consistent interface that transmits all Channel info.

Overview

  • They are immutable: frozen in memory for consistent, reference-safe communication across ViewStream and Channel instances. Use clone() to modify a copy.
  • Every payload carries the same four properties, whatever the source:

Why it Matters

  • Immutability: Enables efficient, cross-component event handling by safely sharing references to data.
  • Action Filtering: Action labels are matched to relevant methods.
  • DOM Context: Includes the triggering DOM element (srcElement) and the event's values (event) for fine-grained control.

Good to know

  • Dataset values are read when the event fires — update a data-* attribute and the next payload carries the new value.
  • An element's data-action value lands at payload.action, separate from the payload's action label. Filters checking { action: X } see the payload's value first — when in doubt, use a payload method.
  • Avoid naming a property payload inside the payload data — Spyne warns, since it collides with the payload property itself. Rename at the source (result, data).

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$ChannelPayloadConstructor
    

STAGE: ChannelPayloadFilter

  • Used by custom Channel and ViewStream instances to filter just the requreid Channel Payloads

ChannelPayloadFilter

Filters allow ViewStream and Channel instances to reactively connect to specific ChannelPayloads.

Channel Payload FilterNew Instance

CONSTRUCTORnew ChannelPayloadFilter (

selectorselector?: string | string[]filters?Object

)

Parameter

Default

Type(s)

Description

selector

(optional)

String | Array | HTMLElement

A selector (or list of selectors) matched against the event target within a ViewStream's DOM — or an actual DOM element.

filters

{}

Object

An object of filtering criteria. Each value can be a string, number, or boolean (compared by equality), or a method that returns true or false.

└─debugLabel

undefined

String

A label for this filter. When set, every matching attempt logs to the console with each filter property's pass/fail — the first thing to reach for when a filter admits nothing or everything.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

ChannelPayloadFilter — Returns a Boolean function that is applied to ChannelPayload properties. The function resolves to true when all of its predicates passes.

This enables Channel and ViewStream instances to refine matching of ChannelPayloads beyond Action labels.

How it works
Add an exact string match or filter method for any property in the ChannelPayload target. All matches need to return true in order for the ChannelPayloadFIlter to pass.

Click on Examples to see the variety of filter options available.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$ChannelPayloadFilterConstructor
    

STAGE: ChannelFetch

  • Creates a channel using content returned from the Fetch API

  • Can be used as CRUD connection to external APIs and services

ChannelFetch

Integrates the native Fetch API into SpyneJS’s Channel platform.
Standardizes API communication, enabling CRUD operations and external data integration within the Channel system.

ChannelFetchNew Instance

CONSTRUCTORnew ChannelFetch (

channelNameString=undefinedpropsObject={}

)

Parameter

Default

Type(s)

Description

channelName

(required)

String

A unique name to identify and access the Channel via getChannel().

props

(required)

Object

Holds all of the properties for the Channel instance.

└─url

(required)

URL

The URL for the Fetch request.

└─map

undefined

Function

Optional mapping function to customize the response before it's emitted.

└─responseType

json

json | text | arrayBuffer | blob | formData

Sets the expected response content type.

└─[Fetch API Options]

Default Fetch Request

String | Objects

All valid fetch options like method, headers, body, mode, etc.

└─disableSanitize

false

Boolean

Allows unsafe tags in a data source when set to true (for data considered secure)

└─pause

false

Boolean

Prevents the fetch from executing until explicitly triggered.

└─debug

false

Boolean

Logs request/response lifecycle to the console.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

ChannelFetch extends the Channel class by automatically triggering fetch requests and returning the response through a standardized ChannelPayload.

This channel can be extended, but it is typically interacted with by sending requests and returning responses via ChannelPayloads.

Every fetch outcome enters the channel system as a conformed ChannelPayload — a success under the response action, a failure under the error action. Both action labels are derived from the channel’s registered name and are registered alongside the channel’s other actions, so both participate in action validation and can be narrowed with addActionListeners and ChannelPayloadFilter.

Requests
Unless paused, the fetch request is sent when created.

Future requests or first requests for paused instances are sent via the "{CHANNEL_NAME}_REQUEST_EVENT" action (the generic "CHANNEL_FETCH_REQUEST_EVENT" label is also registered) sent via sendInfoToChannel.

Response
Responses are cached and returned with the "{CHANNEL_NAME}_RESPONSE_EVENT" action label.

The optional map function conforms the response data before it is emitted.

Error
Fetch failures are returned with the "{CHANNEL_NAME}_ERROR_EVENT" action label.

A failure is any of: a rejected fetch (network failure), a non-OK HTTP response (4xx/5xx), an unparseable response body, an unsupported responseType, or a map function that throws. The map function is not called for error payloads.

The error payload is a conformed, flat object with filterable properties:

  • isChannelFetchError: Always true; discriminates framework fetch errors from response data.
  • errorType: One of FETCH_HTTP_ERROR, FETCH_RESPONSE_PARSE_ERROR, FETCH_UNSUPPORTED_RESPONSE_TYPE, FETCH_UNKNOWN_ERROR.
  • message: Human-readable description of the failure.
  • status / statusText: HTTP status details, when a response was received.
  • url / channelName / responseType: The request context.
  • rawBodyPreview: The response body, truncated to 500 characters.
  • originalErrorMessage: The message of the underlying error, when one exists.

Because ChannelFetch caches its last payload for late subscribers, an error payload becomes the cached payload until a subsequent request succeeds.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$ChannelFetchConstructor
    

STAGE: ChannelFetchUtil

  • This utiliity is used by Channel Fetch to generate observables from the Fetch API

  • Can be added to ChannelFetch modules to create sophisticated APIs

ChannelFetchUtil

A utility class that powers ChannelFetch.
Provides a consistent, composable interface for configuring and executing Fetch API requests as observables.

ChannelFetchUtilNew Instance

CONSTRUCTORnew ChannelFetchUtil (

optionsObject=undefined subscriberFunction=undefined

)

Parameter

Default

Type(s)

Description

options

(required)

Object

Fetch configuration settings.

└─url

(required)

URL

The request URL for the fetch call.

└─map

undefined

Function

A function to modify the response before it's returned.

└─responseType

json

json | text | arrayBuffer | blob | formData

Sets how the fetch response will be parsed.

└─[Fetch API Options]

Base Fetch Options

Object

All valid fetch options like method, headers, body, mode, etc.

└─debug

false

Boolean

Logs fetch request and response to the console.

subscriber

(required)

Function

Callback executed when the fetch completes. Receives either the parsed (and mapped) response or, on failure, the conformed error payload.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

ChannelFetchUtil is an internal utility used by ChannelFetch and custom implementations. It returns an observable that wraps a configured Fetch API call.

This makes it ideal for:

  • Creating testable, standalone fetch logic.
  • Reusing logic across channels or custom fetch setups.
  • Integrating advanced stream behaviors (like retry, debounce, etc.).

Error conforming
The observable never errors out. Every failure — a rejected fetch, a non-OK HTTP response, an unparseable body, an unsupported responseType, or a throwing map function — is caught and conformed into a flat error payload (marked with isChannelFetchError: true and carrying errorType, message, status, statusText, url, rawBodyPreview) that is delivered to the subscriber through the same next path as a successful response.

The map function is only applied to successful responses. ChannelFetch uses this discriminator to route error payloads to its "{CHANNEL_NAME}_ERROR_EVENT" action.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$ChannelFetchUtilSubscribe
    

STAGE: SpyneTrait

  • Organizes logic for codebase

  • Convenient system to test pure functions, that are automatically composed to instances

SpyneTrait

Encapsulates reusable logic as pure functions, easily bindable to ViewStream or Channel instances.

SpyneTraitNew Instance

CONSTRUCTORnew SpyneTrait (

parentContextViewStream | Channel instanceprefix$String=undefined

)

Parameter

Default

Type(s)

Description

parentContext

(required)

ViewStream | Channel

The instance to which functions will be bound.

prefix$

(required)

String

String prepended to all methods to maintain consistency.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

SpyneTraits improve maintainability by allowing logic to be organized, tested, and shared between ViewStream and Channel instances.

What SpyneTraits Provide:

  • Pure Function Encapsulation: Write logic in isolated, testable functions with no side effects.
  • Method Binding: Functions are auto-bound to parentContext (ViewStream or Channel) and namespaced using prefix$.
  • Code Organization: Keeps application logic clean and modular by separating behavior from structure and event flow.
  • RamdaJS Integration: Built-in access to functional utilities like compose, map, filter, etc., using the RamdaJS library.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$SpyneTraitConstructor
    

STAGE: SpyneApp

  • Creates the Channel Pipeline on intialization

  • Takes in the configuration file for channels and other options

  • Registers Channels so that they can be access globally

SpyneApp

Initializes the SpyneJS application and applies configuration settings.

SpyneAppInitialize

init (

configObject={}

)

Parameter

Default

Type(s)

Description

config

{}

Object

Object containing application setup parameters.

└─debug

false

Boolean

Enables developer-friendly logs that assist with app initialization and channel wiring.

└─strict

false

Boolean

Activates a Trusted Types policy to prevent unsafe HTML injection.

└─pluginMethods

[]

Array

Allows plugins to add methods to the application.

Return Parameter(s)

Default

Type(s)

Description

{

}

init

The init() method boots up the SpyneJS application using the provided configuration.

It sets up:

  • Event channels (UI, Route, Window).
  • Application-level flags (debug, strict).
  • Optional plugin methods for global access.

🔒 SpyneJS applications are initialized in memory. The application instance is not attached to the global window object and remains self-contained.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$SpyneAppInit
    

STAGE: SpyneAppProperties

  • Creates the Channel Pipeline on intialization

  • Takes in the configuration file for channels and other options

  • Registers Channels so that they can be access globally

SpyneAppProperties

This is a "Singleton" that can be used to store temporary properties, and to retrieve configuration and navlinks.

SpyneAppPropertiesMethods

setProp (

keyStringvalueAnyisTempBoolean=false

)

Parameter

Default

Type(s)

Description

key

(required)

String

The key under which the property is stored.

value

undefined

Any

The value to be stored.

isTemp

false

Boolean

When true, the first retrieval removes the property from memory.

Return Parameter(s)

Default

Type(s)

Description

{

}

setProp

Allows for the persistent or temporary storage of properties.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$SpyneAppPropertiesSetProp
    

STAGE: SpynePlugin

  • Allows developers to create shareable code and components

SpynePlugin

In early beta, SpynePlugin allows for third-party plugins to be created

SpynePluginNew Instance

CONSTRUCTORnew SpynePlugin (

propsObject={}

)

Parameter

Default

Type(s)

Description

name

(required)

String

The name of the plugin.

props

{}

Object

Holds all of the properties for the plugin instance.

└─pluginName

(required)

String

The unique identifier for the plugin.

└─pluginMethods

undefined

Object

Methods exposed by the plugin to be added to the application.

Return Parameter(s)

Default

Type(s)

Description

{

}

constructor

SpynePlugin allows developers to create shareable ViewStream components, Channels, SpyneTraits and Themes and other functionality.

       new ViewStream({data: "Hello World"})
       .appendToDom(document.body);
       
       // codeplaygroundRef$SpynePluginConstructor