Sponsor
Star

Created With



linkCustom Plugins

You can create your own custom plugins by extending the Plugin class and implementing one of the core plugin interfaces.

info NOTE

Using TypeScript (or an IDE with smart type inference and suggestions) is highly recommended, so that you automatically get the functions you need to fill in.


linkAppend Plugin

Plugins implementing the AppendPlugin interface can add/alter functionality for when something is appended to another node.

callbag-append.plugin.ts
1linkimport { AppendPlugin, Plugin } from 'render-jsx/plugin';

2linkimport { LiveRendererLike } from 'render-jsx';

3link

4linkimport pipe from 'callbag-pipe';

5linkimport subscribe from 'callbag-subscribe';

6link

7link

8linkexport class CallbagAppendPlugin<Node> // --> is generic towards node type

9link extends Plugin<Node, LiveRendererLike<Node>> // --> but requires a `LiveRendererLike` (life-cycle concept)

10link implements AppendPlugin<Node> { // --> and is an append plugin

11link

12link priority() { return Plugin.PriorityFallback; } // --> allows other plugins to supercede this plugin

13link

14link append(target: any, host: Node) { // --> `target` is to be appended to `host`

15link if (typeof target === 'function') { // --> this plugin only operates when `target` is a function (a callbag)

16link const renderer = this.renderer(); // --> get the renderer the plugin is plugged in to

17link const leaf = renderer.leaf(); // --> create a leaf node

18link

19link renderer.hook(leaf, { // --> hooks to life-cycle of the leaf

20link bind: () => pipe(

21link target,

22link subscribe(v => renderer.setContent(leaf, v?.toString()))

23link )

24link });

25link

26link renderer.append(leaf, host); // --> asks renderer to append the leaf node

27link return true; // --> indicates that this plugin handled the append operation

28link }

29link

30link return false; // --> indicates that this plugin does not handle the append operation

31link }

32link}

index.tsx
1linkimport { CommonDOMRenderer } from 'render-jsx/dom';

2linkimport interval from 'callbag-interval';

3link

4linkimport { CallbagAppendPlugin } from './callbag-append.plugin';

5link

6linkconst renderer = new CommonDOMRenderer().plug(() => new CallbagAppendPlugin<Node>());

7link

8linkrenderer

9link .render(<div>You've been here for {interval(1000)} seconds.</div>)

10link .on(document.body);

Try It!

info IMPORTANT

Append plugins MUST return a boolean from their .append() method. Returning true means the plugin took over the appending process and there is no need to try other plugins, false means the plugin could not handle the append and other plugins should be tried.


info NOTE

The .priority() method should return something between 0 and 1, and is used by renderers to prioritize this plugin over others. 0 means fallback, i.e. if no other plugin took over the operation then this plugin should be tested, and 1 means this is the first plugin that should be tested. .priority() method should be defined by all plugin types.


linkProp Plugin

Plugins implementing PropPlugin interface can affect how properties of nodes are set:

callbag-prop.plugin.ts
1linkimport { PropPlugin, Plugin } from 'render-jsx/plugin';

2linkimport { LiveRendererLike } from 'render-jsx';

3link

4linkimport pipe from 'callbag-pipe';

5linkimport subscribe from 'callbag-subscribe';

6link

7link

8linkexport class CallbagPropPlugin<Node> // --> is generic towards node type

9link extends Plugin<Node, LiveRendererLike<Node>> // --> but requires a `LiveRendererLike` (life-cycle concept)

10link implements PropPlugin<Node> { // --> and is a `PropPlugin`

11link

12link priority() { return Plugin.PriorityFallback; } // --> allows other plugins to supercede this plugin

13link

14link setProp(node: Node, prop: string, target: any) { // --> we want to set property `prop` on `node` to `target`

15link if (typeof target === 'function') { // --> check if it is a function (i.e. a callbag)

16link const renderer = this.renderer(); // --> get the renderer we are plugged into

17link

18link renderer.hook(node, { // --> attach to life-cycle of the node

19link bind: () => pipe(

20link target,

21link subscribe(v => renderer.setProp(node, prop, v?.toString()))

22link )

23link });

24link

25link return true; // --> indicates that we handled the setProp operation

26link }

27link

28link return false; // --> indicates that we couldn't handle the setProp operation

29link }

30link}

index.tsx
1linkimport { CommonDOMRenderer } from 'render-jsx/dom';

2linkimport interval from 'callbag-interval';

3linkimport pipe from 'callbag-pipe';

4linkimport map from 'callbag-map';

5link

6linkimport { CallbagPropPlugin } from './callbag-prop.plugin';

7link

8linkconst renderer = new CommonDOMRenderer().plug(() => new CallbagPropPlugin<Node>());

9link

10linkconst style = pipe(

11link interval(1000),

12link map(v => v % 2 === 0 ? 'color: red' : 'color: blue')

13link);

14link

15linkrenderer.render(

16link <div style={style}>

17link Hellow There!

18link </div>

19link).on(document.body);

Try It!

info IMPORTANT

Prop plugins MUST return a boolean from their .setProp() method. Returning true means the plugin took over setting the property and there is no need to try other plugins, false means the plugin could not set given property on given node and other plugins should be tried.


linkStyles and Classes

Plugins implementing SetStylePlugin interface can affect how particular style values are set via style objects:

callbag-style.plugin.ts
1linkimport { Plugin } from 'render-jsx/plugin';

2linkimport { SetStylePlugin } from 'render-jsx/dom/plugins';

3linkimport { LiveRendererLike } from 'render-jsx';

4link

5linkimport pipe from 'callbag-pipe';

6linkimport subscribe from 'callbag-subscribe';

7link

8link

9linkexport class CallbagStylePlugin

10link extends Plugin<Node, LiveRendererLike<Node>>

11link implements SetStylePlugin<LiveRendererLike<Node>> {

12link

13link priority() { return Plugin.PriorityFallback; }

14link

15link setStyle(

16link node: HTMLElement,

17link style: string,

18link target: any,

19link set: (value: string|object) => void

20link ): boolean {

21link if (typeof target === 'function') {

22link const renderer = this.renderer();

23link

24link renderer.hook(node, {

25link bind: () => pipe(

26link target,

27link subscribe(v => set(v?.toString()))

28link )

29link });

30link

31link return true;

32link }

33link

34link return false;

35link }

36link}

index.tsx
1linkimport { CommonDOMRenderer } from 'render-jsx/dom';

2linkimport interval from 'callbag-interval';

3linkimport pipe from 'callbag-pipe';

4linkimport map from 'callbag-map';

5link

6linkimport { CallbagStylePlugin } from './callbag-style.plugin';

7link

8linkconst renderer = new CommonDOMRenderer()

9link.plug(() => new CallbagStylePlugin<Node>());

10link

11linkconst color = pipe(

12link interval(1000),

13link map(v => v % 2 === 0 ? 'red' : 'blue')

14link);

15link

16linkrenderer.render(

17link <div style={{color: color}}>

18link Hellow There!

19link </div>

20link).on(document.body);

Try It!

Similarly, plugins implementing AddClassPlugin or ToggleClassPlugin can affect how classes are set. Both of these plugins are also exported from render-jsx/dom/plugins.

info IMPORTANT

You MUST have StylePlugin plugged into your renderer for any SetStylePlugin to have any effect. Similarly, you MUST have ClassPlugin plugged into your renderer for any AddClassPlugin or ToggleClassPlugin to have any effect.


info IMPORTANT

Similar to prop plugins, style and class plugins MUST return a boolean from their .setStyle(), .addClass() or their .addClassToggle() methods, were true indicates that the plugin is handling setting the particular class/style and false means other plugins should be attempted.


linkContent Plugin

Plugins implementing ContentPlugin can add functionality for setting the content of a node. The meaning of content of a node is context-dependent, for example in DOM it is the same thing as inner HTML for elements and text content of text nodes.

callbag-content.plugin.ts
1link import { ContentPlugin, Plugin } from 'render-jsx/plugin';

2linkimport { LiveRendererLike } from 'render-jsx';

3link

4linkimport pipe from 'callbag-pipe';

5linkimport subscribe from 'callbag-subscribe';

6link

7link

8linkexport class CallbagContentPlugin<Node> // --> is generic towards node type

9link extends Plugin<Node, LiveRendererLike<Node>> // --> but needs a `LiveRendererLike` (life-cylce concept)

10link implements ContentPlugin<Node> { // --> and is a `ContentPlugin`

11link

12link priority() { return Plugin.PriorityFallback; } // --> allows for other plugins to supercede this plugin

13link

14link setContent(node: Node, target: any) { // --> set `node`'s content to `target`

15link if (typeof target === 'function') { // --> if `target` is a function (i.e. a callbag)

16link const renderer = this.renderer();

17link

18link renderer.hook(node, { // --> bind to `node`'s lifecycle

19link bind: () => pipe(

20link target,

21link subscribe(v => renderer.setContent(node, v?.toString()))

22link )

23link });

24link

25link return true; // --> indicates this plugin set the content

26link }

27link

28link return false; // --> indicates this plugin could not set the content

29link }

30link}

index.tsx
1linkimport { CommonDOMRenderer } from 'render-jsx/dom';

2linkimport interval from 'callbag-interval';

3linkimport pipe from 'callbag-pipe';

4linkimport map from 'callbag-map';

5link

6linkimport { CallbagContentPlugin } from './callbag-content.plugin';

7link

8linkconst renderer = new CommonDOMRenderer()

9link .plug(() => new CallbagContentPlugin<Node>());

10link

11linkconst content = pipe(

12link interval(1000),

13link map(v => `You have been here for ${v} seconds.`)

14link);

15link

16linkrenderer.render(

17link <div _content={content}/>

18link).on(document.body);

Try It!

info IMPORTANT

Content plugins MUST return a boolean from their .setContent() method. Returning true means the plugin set the content, and false means it couldn't and the renderer should try other plugins.


linkOther Plugin Types

Plugins implementing CreatePlugin can modify how nodes are created. Returning undefined means the plugin could not create the node and the renderer should try other plugins.

1linkinterface CreatePlugin<Node, Renderer> extends Plugin<Node, Renderer> {

2link create(tag: any, props?: {[prop: string]: any}, ...children: any[]): Node | undefined;

3link}


Plugins implementing LeafPlugin can determine how leaf nodes are made. Only the highest priority LeafPlugin will be used by the renderer, its fallback mechanism will also be discarded.

1linkinterface LeafPlugin<Node, Renderer> extends Plugin<Node, Renderer> {

2link leaf(): Node;

3link}


Plugins implementing FragmentPlugin can determine how fragments are created. The result of this plugin will be passed to renderer's .create() method as the tag. Only the highest priority FragmentPlugin will be used by the renderer, its fallback mechanism will also be discarded.

1linkinterface FragmentPlugin<Node, Renderer> extends Plugin<Node, Renderer> {

2link fragment(): Node;

3link}


Plugins implementingPostCreatePlugin can run some post-processing on nodes after they are created.

1linkinterface PostCreatePlugin<Node, Renderer> extends Plugin<Node, Renderer> {

2link postCreate(node: Node): void;

3link}


Plugins implementing PostRenderPlugin can run some post-processing on nodes after they are rendered (might happen multiple times for a single node).

1linkexport interface PostRenderPlugin<Node, Renderer> extends Plugin<Node, Renderer> {

2link postRender(node: Node): void;

3link}

Custom PluginsAppend PluginProp PluginStyles and ClassesContent PluginOther Plugin Types

Home Overview Installation

Usagechevron_right

Usage Overview

DOM Renderingchevron_right
Custom Rendererschevron_right