npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

snabbdom-jsx

v0.4.2

Published

Write snabbdom views using JSX and Babel

Downloads

6,491

Readme

npm version

Write Snabbdom virtual DOM with Babel's JSX.

Snabbdom is a small Virtual DOM library. Unlike React, it's not a full View framework, it just focuses on the core virtual DOM problem : construct virtual DOM trees (virtual nodes) and patch the real DOM with them. it's entirely up to you to decide when those operations will happen. The main benefit is that you can adopt whatever architectural UI pattern you like in your application.

Babel is a JavaScript compiler that converts modern JavaScript (ES2015 and beyond) into compatible JavaScript (ES5) code. A nice feature of Babel is that it supports React JSX syntax and in the same time allows you to take the result of this JSX (attributes + body) and do whatever you like with it. Snabbdom-jsx transforms this JSX data into Snabbdom virtual nodes.

Features:

  • Transforms Babel JSX templates into Snabbdom virtual nodes
  • Straightforward mapping from JSX attributes to Snabbdom data attributes using namespaces
  • JSX Components are simple functions (attributes, children) => vnode. No more messy classes.

Usage

installation

npm install snabbdom-jsx

Hello example (see the complete example here)

/** @jsx html */

import { html } from 'snabbdom-jsx';

const patch = snabbdom.init([...]);

const vnode = <div>Hello JSX</div>

patch(document.getElementById('placeholder'), vnode);

The /** @jsx html */ pragma at the top tells Babel to use the html function instead of the React.createElement default. The html function takes arguments passed from Babel and generates virtual nodes as expected by Snabbdom's patch function.

Mapping JSX attributes

A quick reminder: in snabbdom, most of the functionality like toggling classes, styles and setting properties on DOM elements is delegated to separate modules.

For example

const myInput = h('input', {
  props: { type: 'text' }       // handled by the props module
  on: { change: someCallback }, // handled by the eventlisteners module
  class: { class1: isEnabled }  // handled by the class module
  ...
})

Each module handles a portion of the data attributes (the 2nd parameter to h). And each portion is stored inside a namespace, for example, event attributes are placed inside the on namespace, class attributes inside the class namespace and so on.

By default all attributes listed in the JSX element are placed inside the props namespace.

<input type="text" />

Is equivalent to

h('input', { props: { type: 'text' } })

To attach event listeners, we use the on- prefix

<button on-click={ callback } />

// is equivalent to

h('button', { on: { click: callback } })

This is a generic rule to map a JSX attribute to a specific module, you need to prefix the attribute with pref- where pref is the namespace used by the module in Snabbdom. As in the example above, all attributes with the on- prefix (i.e. event listeners) will be placed inside the the on namespace. This gives us a simple and extensible pattern to support other custom modules.

Another example using the class namespace

<div
  class-visible={isVisible}
  class-enabled={isEnabled}>

  ...
</div>

// is equivalent to

h('div', {
  class: { visible: isVisible, enabled: isEnabled }
}, [...])

But you can also specify an unique object the same way as in the h function, this is useful when you have a dynamic object

<div
  style={ ({fontWeight: 'bold', color: 'red'}) }>

  ...
</div>

// is equivalent to

h('div', {
  style: {fontWeight: 'bold', color: 'red'}
}, [...])

You can mix both styles, the result will be a merge of all attributes

<div
  class={ ({visible: isVisible}) }
  class-enabled={isEnabled}>

  ...
</div>

Id and static classes (sel attribute)

In Snabbdom you can create an element using a css-like syntax

h('div#id.class1.class2', ...)

This will set the element id add the class names to its classList property. Unlike classes specified in the class namespace, those are static classes meaning they will not be re-updated during patch operations.

In JSX you can use the selector attribute to set the element's id and add static classes

<div selector="#id.class1.class2" />

You can also specify static classes via the classNames property

<div classNames="class1 class2" />

You can also provide an array to classNames instead of a string

const classes = ['class1', 'class2'];
<div classNames={classes} />

it's important to remember to not pass dynamic values to selector or classNames. As this can lead to some unexpected issues. If you want to set dynamic classes, use the class module instead.

JSX Components

In React/JSX you can create components and use them inside other components

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

React.render(<HelloMessage name="John" />, mountNode);

Instead of classes, Snabbdom-jsx components are simple functions of type
(attributes, children) => vnode.

//HelloMessage : (attrs, body) -> vnode
const HelloMessage = ({name}) =>
  <div on-click={ _ => alert('Hi ' + name) }>
    {name}
  </div>;


var vnode = <HelloMessage name="Yassine" />

As in React, note that all components must start with a capital letter, while regular HTML tags start with lower case letters. This the way Babel also distinguish component invocation from simple tag creation.

Perhaps of less obvious utility, but instead of a function, a component can also be an object with a view or render function. I added this in order to support nesting in UI patterns; especially in the Elm architecture, where a component is an object with a view (or render) function (among others)

for example you can have a Task component

Task.view = ({task}) => ...
Task.update = ...

and use it inside a Todos component like this

import Task from './task'

Todos.view = ({todos}) => todos.map(todo =>
                              <Task todo={todo} key={todo.id} />)

As illustrated above, you can also add a key attribute directly to a Component. It will be copied inside the resulting vnode

If you're wondering how Components would fit in a large application, you can look into the todomvc example. The application is implemented using the Elm architecture. For more information see React-less Virtual DOM with Snabbdom : functions everywhere!