| `create`| a DOM element has been created based on a vnode | `emptyVnode, vnode` |
| `create` | a DOM element has been created based on a vnode | `emptyVnode, vnode` |
| `insert`| an element has been inserted into the DOM | `vnode` |
| `insert` | an element has been inserted into the DOM | `vnode` |
| `prepatch`| an element is about to be patched | `oldVnode, vnode` |
| `prepatch` | an element is about to be patched | `oldVnode, vnode` |
| `update`| an element is being updated | `oldVnode, vnode` |
| `update` | an element is being updated | `oldVnode, vnode` |
| `postpatch` | an element has been patched | `oldVnode, vnode` |
| `postpatch` | an element has been patched | `oldVnode, vnode` |
| `destroy`| an element is directly or indirectly being removed | `vnode` |
| `destroy` | an element is directly or indirectly being removed | `vnode` |
| `remove`| an element is directly being removed from the DOM | `vnode, removeCallback` |
| `remove` | an element is directly being removed from the DOM | `vnode, removeCallback` |
| `post`| the patch process is done | none |
| `post` | the patch process is done | none |
The following hooks are available for modules: `pre`, `create`,
The following hooks are available for modules: `pre`, `create`,
`update`, `destroy`, `remove`, `post`.
`update`, `destroy`, `remove`, `post`.
@ -462,6 +494,7 @@ h('div', [
```
```
Each handler is called not only with the given arguments but also with the current event and vnode appended to the argument list. It also supports using multiple listeners per event by specifying an array of handlers:
Each handler is called not only with the given arguments but also with the current event and vnode appended to the argument list. It also supports using multiple listeners per event by specifying an array of handlers:
SVG just works when using the `h` function for creating virtual
SVG just works when using the `h` function for creating virtual
nodes. SVG elements are automatically created with the appropriate
nodes. SVG elements are automatically created with the appropriate
@ -529,13 +560,13 @@ var vnode = h('div', [
See also the [SVG example](./examples/svg) and the [SVG Carousel example](./examples/carousel-svg/).
See also the [SVG example](./examples/svg) and the [SVG Carousel example](./examples/carousel-svg/).
#### Using Classes in SVG Elements
### Classes in SVG Elements
Certain browsers (like IE <=11) [do not support `classList` property in SVG elements](http://caniuse.com/#feat=classlist).
Certain browsers (like IE <=11) [do not support `classList` property in SVG elements](http://caniuse.com/#feat=classlist).
Because the _class_ module internally uses `classList`, it will not work in this case unless you use a [classList polyfill](https://www.npmjs.com/package/classlist-polyfill).
Because the _class_ module internally uses `classList`, it will not work in this case unless you use a [classList polyfill](https://www.npmjs.com/package/classlist-polyfill).
(If you don't want to use a polyfill, you can use the `class` attribute with the _attributes_ module).
(If you don't want to use a polyfill, you can use the `class` attribute with the _attributes_ module).
### Thunks
## Thunks
The `thunk` function takes a selector, a key for identifying a thunk,
The `thunk` function takes a selector, a key for identifying a thunk,
a function that returns a vnode and a variable amount of state
a function that returns a vnode and a variable amount of state
@ -581,22 +612,24 @@ relevant if you are rendering a complicated view that takes
significant computational time to generate.
significant computational time to generate.
## Virtual Node
## Virtual Node
**Properties**
**Properties**
- [sel](#sel--string)
- [data](#data--object)
- [children](#children--array)
- [text](#text--string)
- [elm](#elm--element)
- [key](#key--string--number)
#### sel : String
* [sel](#sel--string)
* [data](#data--object)
* [children](#children--array)
* [text](#text--string)
* [elm](#elm--element)
* [key](#key--string--number)
### sel : String
The `.sel` property of a virtual node is the CSS selector passed to
The `.sel` property of a virtual node is the CSS selector passed to
[`h()`](#snabbdomh) during creation. For example: `h('div#container',
[`h()`](#snabbdomh) during creation. For example: `h('div#container',
{}, [...])` will create a a virtual node which has `div#container` as
{}, [...])` will create a a virtual node which has `div#container` as
its `.sel` property.
its `.sel` property.
#### data : Object
### data : Object
The `.data` property of a virtual node is the place to add information
The `.data` property of a virtual node is the place to add information
for [modules](#modules-documentation) to access and manipulate the
for [modules](#modules-documentation) to access and manipulate the
@ -606,6 +639,7 @@ attributes, etc.
The data object is the (optional) second parameter to [`h()`](#snabbdomh)
The data object is the (optional) second parameter to [`h()`](#snabbdomh)
For example `h('div', {props: {className: 'container'}}, [...])` will produce a virtual node with
For example `h('div', {props: {className: 'container'}}, [...])` will produce a virtual node with
```js
```js
{
{
"props": {
"props": {
@ -613,9 +647,10 @@ For example `h('div', {props: {className: 'container'}}, [...])` will produce a
}
}
}
}
```
```
as its `.data` object.
as its `.data` object.
#### children : Array<vnode>
### children : Array<vnode>
The `.children` property of a virtual node is the third (optional)
The `.children` property of a virtual node is the third (optional)
parameter to [`h()`](#snabbdomh) during creation. `.children` is
parameter to [`h()`](#snabbdomh) during creation. `.children` is
@ -640,7 +675,7 @@ create a virtual node with
as its `.children` property.
as its `.children` property.
#### text : string
### text : string
The `.text` property is created when a virtual node is created with
The `.text` property is created when a virtual node is created with
only a single child that possesses text and only requires
only a single child that possesses text and only requires
@ -649,14 +684,14 @@ only a single child that possesses text and only requires
For example: `h('h1', {}, 'Hello')` will create a virtual node with
For example: `h('h1', {}, 'Hello')` will create a virtual node with
`Hello` as its `.text` property.
`Hello` as its `.text` property.
#### elm : Element
### elm : Element
The `.elm` property of a virtual node is a pointer to the real DOM
The `.elm` property of a virtual node is a pointer to the real DOM
node created by snabbdom. This property is very useful to do
node created by snabbdom. This property is very useful to do
calculations in [hooks](#hooks) as well as
calculations in [hooks](#hooks) as well as
[modules](#modules-documentation).
[modules](#modules-documentation).
#### key : string | number
### key : string | number
The `.key` property is created when a key is provided inside of your
The `.key` property is created when a key is provided inside of your
[`.data`](#data--object) object. The `.key` property is used to keep
[`.data`](#data--object) object. The `.key` property is used to keep
@ -670,7 +705,6 @@ an object, where `.key` is the key and the value is the
For example: `h('div', {key: 1}, [])` will create a virtual node
For example: `h('div', {key: 1}, [])` will create a virtual node
object with a `.key` property with the value of `1`.
object with a `.key` property with the value of `1`.
## Structuring applications
## Structuring applications
Snabbdom is a low-level virtual DOM library. It is unopinionated with
Snabbdom is a low-level virtual DOM library. It is unopinionated with
@ -682,11 +716,11 @@ Here are some approaches to building applications with Snabbdom.
a repository containing several example applications that
a repository containing several example applications that
demonstrates an architecture that uses Snabbdom.
demonstrates an architecture that uses Snabbdom.
* [Cycle.js](https://cycle.js.org/) –
* [Cycle.js](https://cycle.js.org/) –
"A functional and reactive JavaScript framework for cleaner code"
"A functional and reactive JavaScript framework for cleaner code"
uses Snabbdom
uses Snabbdom
* [Vue.js](http://vuejs.org/) use a fork of snabbdom.
* [Vue.js](http://vuejs.org/) use a fork of snabbdom.
redux-like architecture on top of snabbdom bindings.
redux-like architecture on top of snabbdom bindings.
* [kaiju](https://github.com/AlexGalays/kaiju) -
* [kaiju](https://github.com/AlexGalays/kaiju) -
Stateful components and observables on top of snabbdom
Stateful components and observables on top of snabbdom
* [Tweed](https://tweedjs.github.io) –
* [Tweed](https://tweedjs.github.io) –
@ -710,11 +744,13 @@ using Snabbdom.
## Common errors
## Common errors
```
```text
Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node':
Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node':
The node before which the new node is to be inserted is not a child of this node.
The node before which the new node is to be inserted is not a child of this node.
```
```
The reason for this error is reusing of vnodes between patches (see code example), snabbdom stores actual dom nodes inside the virtual dom nodes passed to it as performance improvement, so reusing nodes between patches is not supported.
The reason for this error is reusing of vnodes between patches (see code example), snabbdom stores actual dom nodes inside the virtual dom nodes passed to it as performance improvement, so reusing nodes between patches is not supported.
```js
```js
var sharedNode = h('div', {}, 'Selected');
var sharedNode = h('div', {}, 'Selected');
var vnode1 = h('div', [
var vnode1 = h('div', [
@ -730,7 +766,9 @@ var vnode2 = h('div', [
patch(container, vnode1);
patch(container, vnode1);
patch(vnode1, vnode2);
patch(vnode1, vnode2);
```
```
You can fix this issue by creating a shallow copy of the object (here with object spread syntax):
You can fix this issue by creating a shallow copy of the object (here with object spread syntax):
```js
```js
var vnode2 = h('div', [
var vnode2 = h('div', [
h('div', {}, ['One']),
h('div', {}, ['One']),
@ -738,7 +776,9 @@ var vnode2 = h('div', [
h('div', {}, ['Three']),
h('div', {}, ['Three']),
]);
]);
```
```
Another solution would be to wrap shared vnodes in a factory function:
Another solution would be to wrap shared vnodes in a factory function: