Star

Created With

Getting Started


linkSetup a project

The easiest way for setting up a new callbag-jsx project is to use one of the following starter templates on GitHub. Open the repo of your choice, and follow the instructions on the README.

TypeScript TemplateJavaScript Template

πŸ‘‰ Read the installation guide for other methods of installing callbag-jsx.



linkHellow World!

A simple Hellow World! app looks like this:

1linkimport { makeRenderer } from 'callbag-jsx';

2link

3linkconst renderer = makeRenderer();

4linkrenderer.render(<div>Hellow World!</div>).on(document.body);

πŸ‘‰ Here is what happens:

  1. We create a renderer object to render the UI.
  2. We tell the renderer to render a <div/> element on document.body.

info ALWAYS name your renderer object renderer.




linkJSX

In the Hellow World! exmaple above, we created a <div/> element inside JavaScript. This is because we are using an extension of JavaScript called JSX, which allows us to have JavaScript variables, expressions, etc inside our layout code seamlessly:

1linkconst name = 'Jack';

2link

3linkrenderer.render(

4link <div>Hellow {name}!</div>

5link).on(document.body);

πŸ‘‰ JSX expressions create HTML elements, so you can for example store them in variables:

1linkconst x = <div>Hellow {name}!</div>;

2linkrenderer.render(x).on(document.body);

Learn More

info You MUST have a renderer named renderer in any scope with JSX.




linkDynamic Content

Callbags are models for stuff that change. When you embed them within your JSX, the resulting DOM will also change when the embeded callbags change:

1linkimport state from 'callbag-state';

2link

3linkconst count = state(0);

4linkrenderer.render(

5link <div>You have been here {count} seconds!</div>

6link).on(document.body);

7link

8linksetInterval(() => count.set(count.get() + 1), 1000);

PlaygroundLearn More

πŸ‘‰ This works similarly with attributes:

1link<div title={count}>Hover to see how many seconds you've been here.</div>

Learn More



linkDOM Events

Capture DOM events by providing an event listener function:

1linkconst count = state(0);

2link

3linkrenderer.render(

4link <div onclick={() => count.set(count.get() + 1)}>

5link You have clicked this {count} times!

6link </div>

7link).on(document.body);

PlaygroundLearn More



linkUser Input

Fetch user input using _state attribute:

1linkconst input = state('');

2link

3linkrenderer.render(<>

4link <input _state={input} type='text' placeholder='type something ...'/>

5link <div>You typed: {input}</div>

6link</>).on(document.body);

PlaygroundLearn More



linkDynamic Expressions

Use expr to dynamic expressions from other callbags:

1linkimport { expr } from 'callbag-common';

2link

3linkconst input = state('');

4linkconst length = expr($ => $(input).length);

5link

6linkrenderer.render(<>

7link <input _state={input} type='text' placeholder='type something ...'/>

8link <div>You typed {length} characters.</div>

9link</>).on(document.body);

PlaygroundLearn More



linkDynamic Styles & Classes

Set dynamic styles for your element by providing a style map with some of its values being callbags:

1linkconst count = state(0);

2link

3linkconst add = () => count.set(count.get() + 1);

4linkconst color = expr($ => $(count) % 2 ? 'red' : 'green');

5link

6linkrenderer.render(

7link <div onclick={add} style={{ color }}>

8link You have clicked {count} times!

9link </div>

10link).on(document.body);

PlaygroundLearn More

πŸ‘‰ Use callbags similarly in class maps for dynamically changing classes:

1link<div class={{ odd: expr($ => $(i) % 2 === 0) }}/>

Learn More



linkConditional DOM

<Conditional/> component enables creating elements that appear conditionally:

1linkimport { Conditional } from 'callbag-jsx';

2link

3linkconst show = state(true);

4link

5linkrenderer.render(<>

6link <input type='checkbox' _state={show}/> Show stuff

7link <Conditional if={show}

8link then={() => <div>πŸ¦„πŸͺ•Stuff Are Shown ... πŸͺ•πŸ¦„</div>}

9link else={() => <div>Not showing stuff</div>}

10link />

11link</>).on(document.body);

PlaygroundLearn More



linkDynamic Lists (Loops)

Use <List/> component to create dynamic lists:

1linkimport { List } from 'callbag-jsx';

2link

3linkconst records = state([]);

4linkconst add = () => records.set(records.get().concat(new Date()));

5linkconst clear = () => records.set([]);

6link

7linkrenderer.render(<>

8link <button onclick={add}>Add</button>

9link <button onclick={clear}>Clear</button>

10link <ul>

11link <List of={records} each={record => <li>{record}</li>}/>

12link </ul>

13link</>).on(document.body);

PlaygroundLearn More


linkData Fetching

Use <Wait/> component for rendering based on data that is fetched asynchronously.

1linkimport { Wait } from 'callbag-jsx';

2link

3linkrenderer.render(

4link <Wait

5link for={fetch('https://pokeapi.co/api/v2/pokemon/charizard').then(res => res.json())}

6link with={() => <>Loading ...</>}

7link then={pokemon => <h1>{pokemon.name}</h1>}

8link />

9link).on(document.body);

PlaygroundLearn More


linkComponents

In callbag-jsx, components are functions that are used to create similar parts of the UI:

1linkconst records = state([]);

2linkconst add = () => records.set(records.get().concat(new Date()));

3linkconst clear = () => records.set([]);

4link

5linkfunction Record({ record }, renderer) {

6link const remove = () => records.set(records.get().filter(r => r !== record.get()));

7link

8link return <div>{ record } <button onclick={remove}>X</button></div>

9link}

10link

11linkrenderer.render(

12link <>

13link <button onclick={add}>Add</button>

14link <button onclick={clear}>Clear</button>

15link <List of={records} each={record => <Record record={record}/>}/>

16link </>

17link).on(document.body);

PlaygroundLearn More

info Components MUST have a second argument called renderer.







Setup a projectHellow World!JSXDynamic ContentDOM EventsUser InputDynamic ExpressionsDynamic Styles & ClassesConditional DOMDynamic Lists (Loops)Data FetchingComponentsQuick Links

Home Getting Started


Introductionchevron_right

Basicschevron_right

Reactivitychevron_right

Componentschevron_right

In-Depthchevron_right

Metachevron_right