{"id":13827844,"url":"https://github.com/skatejs/dom-diff","last_synced_at":"2025-04-12T14:10:50.647Z","repository":{"id":57362193,"uuid":"41280887","full_name":"skatejs/dom-diff","owner":"skatejs","description":"Library for efficiently diffing and patching virtual and real DOM fragments.","archived":false,"fork":false,"pushed_at":"2018-08-27T22:20:23.000Z","size":764,"stargazers_count":100,"open_issues_count":6,"forks_count":7,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-26T08:47:37.718Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skatejs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-24T03:57:10.000Z","updated_at":"2025-01-05T00:16:21.000Z","dependencies_parsed_at":"2022-09-26T16:40:47.074Z","dependency_job_id":null,"html_url":"https://github.com/skatejs/dom-diff","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skatejs%2Fdom-diff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skatejs%2Fdom-diff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skatejs%2Fdom-diff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skatejs%2Fdom-diff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skatejs","download_url":"https://codeload.github.com/skatejs/dom-diff/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248578873,"owners_count":21127713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T09:02:14.927Z","updated_at":"2025-04-12T14:10:50.621Z","avatar_url":"https://github.com/skatejs.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Dom Diff\n\nSkate's DOM Diff is a virtual DOM library for diffing, patching and converting between virtual and real DOM trees.\n\n[![Sauce Test Status](https://saucelabs.com/browser-matrix/skatejs-dom-diff.svg)](https://saucelabs.com/u/skatejs-dom-diff)\n\n- Serialise to and from read DOM trees\n- Diff virtual trees and patch real trees\n- Web worker support\n\n```sh\nnpm install skatejs-dom-diff\n```\n\n## Usage\n\nWhere `options` are accepted, you may provide:\n\n- `done` If specified, diffing is performed in a web worker and this callback is called when it's done.\n\n### `diff(source, target, options)`\n\nDiffs two virtual trees.\n\n```js\n/** @jsx h **/\nimport { diff, h } from 'skatejs-dom-diff';\n\nconst source = \u003cdiv\u003e\u003cspan\u003esource\u003c/span\u003e\u003c/div\u003e;\nconst target = \u003cdiv\u003e\u003cspan\u003etarget\u003c/span\u003e\u003c/div\u003e;\nconst instructions = diff(source, target);\n```\n\nThe `patchInstructions` is an `array` that can be passed to `patch()` to update the `source` tree. Before passing the instructions to `patch()`, however, your source tree must be associated to real DOM nodes. This can be done by using `mount()` or by converting them to a tree using `toDom()`.\n\n### `fragment([virtualNodeOrNodes])`\n\nCreates a virtual fragment. You can pass nothing to create an empty fragment:\n\n```js\nimport { fragment } from 'skatejs-dom-diff';\n\nconst vFrag = fragment();\n```\n\nA single virtual node:\n\n```js\nimport { fragment } from 'skatejs-dom-diff';\n\nconst vFrag = fragment(\u003cdiv /\u003e);\n```\n\nAn array of virtual nodes:\n\n```js\nimport { fragment } from 'skatejs-dom-diff';\n\nconst vFrag = fragment([\u003cdiv /\u003e, \u003cspan /\u003e]);\n```\n\nOr even a virtual fragment:\n\n```js\nimport { fragment } from 'skatejs-dom-diff';\n\nconst vFrag = fragment(fragment(\u003cdiv /\u003e));\n```\n\n### `h(name, props, ...childrenOrText)`\n\nCreates a virtual node.\n\n```js\n// \u003cdiv class=\"my-class\"\u003etext or...\u003cspan /\u003e\u003c/div\u003e\nh('div', { className: 'my-class' }, 'text or...', h('span'));\n```\n\nOr you could just use JSX:\n\n```js\n/** @jsx h **/\n// \u003cdiv class=\"my-class\"\u003etext or...\u003cspan /\u003e\u003c/div\u003e\n\u003cdiv className=\"my-class\"\u003etext or...\u003cspan /\u003e\u003c/div\u003e\n```\n\n#### Attributes\n\nBy default, `h` only sets properties, but you can specify attributes you want to set by passing the special `attributes` prop:\n\n```js\n// \u003cdiv class=\"my-class\" /\u003e\n\u003cdiv attributes={{ class: 'my-class' }} /\u003e\n```\n\n#### Aria attributes\n\nYou can pass `aria-*` attributes using `attributes` but you can also specify the `aria` prop:\n\n```js\n// \u003cdiv aria-label=\"my label\" /\u003e\n\u003cdiv aria={{ label: 'my label' }} /\u003e\n```\n\n#### Data attributes\n\nLike the `aria` prop, you can also use the `data` prop:\n\n```js\n// \u003cdiv data-something=\"my data\" /\u003e\n\u003cdiv data={{ something: 'my data' }} /\u003e\n```\n\n#### Events\n\nEvents are bound using the special `events` prop:\n\n```js\nconst click = e =\u003e doSomethingWith(e);\n\u003cdiv events={{ click }} /\u003e\n```\n\n### `merge()`\n\nThe `merge()` function is convenience for calling `diff()` and `patch()` sequentially. As with `diff()`, you must ensure the `source` virtual tree has been associated to real nodes first.\n\n```js\n/** @jsx h **/\nimport { diff, h } from 'skatejs-dom-diff';\n\nconst source = \u003cdiv\u003e\u003cspan\u003esource\u003c/span\u003e\u003c/div\u003e;\nconst target = \u003cdiv\u003e\u003cspan\u003etarget\u003c/span\u003e\u003c/div\u003e;\nconst dom = mount(source);\nmerge(source, target);\n```\n\n### `mount(vdom[, root])`\n\nMounts the `vdom` to the real `root` DOM node. It returns the `root` node. If the `root` node was not specified, it automatically creates a `\u003cdiv /\u003e` and returns it.\n\n```js\n/** @jsx h **/\nimport { h, mount } from 'skatejs-dom-diff';\n\nconst div = mount(\u003cp\u003esome text\u003c/p\u003e);\n```\n\nIs the same thing as:\n\n```js\n/** @jsx h **/\nimport { h, mount } from 'skatejs-dom-diff';\n\nconst div = document.createElement('div');\nmount(\u003cp\u003esome text\u003c/p\u003e, div);\n```\n\nIt's more than likely that you'll just mount it directly to the document:\n\n```js\n/** @jsx h **/\nimport { h, mount } from 'skatejs-dom-diff';\n\nmount(\u003cp\u003esome text\u003c/p\u003e, document.getElementById('app'));\n```\n\n### `patch()`\n\nTakes instructiosn created using `diff()` and performs them on the associated DOM nodes that each instructions is for.\n\n```js\n/** @jsx h **/\nimport { diff, h, mount, patch } from 'skatejs-dom-diff';\n\nconst source = \u003cp\u003esource tree\u003c/p\u003e;\nconst target = \u003cp\u003etarget tree\u003c/p\u003e;\nconst instructions = diff(source, target);\n\nmount(source, document.getElementById('app'));\npatch(instructions);\n```\n\n### `render()`\n\nA highly convenient function for continually rendering a given template.\n\n```js\n/** @jsx h **/\nimport { h, render } from 'skatejs-dom-diff';\n\nconst root = document.getElementById('app');\nconst renderer = render((root) =\u003e (\n  \u003cp\u003e{root.someProp}\u003c/p\u003e\n));\n\n// Set the prop to render with\nroot.someProp = 'test 1';\n\n// Initial render: \u003cp\u003etest 1\u003c/p\u003e\nrenderer(root);\n\n// Update the prop\nroot.someProp = 'test 2';\n\n// Re-render: \u003cp\u003etest 2\u003c/p\u003e\nrenderer(root);\n```\n\n### `text()`\n\nReturns a virtual text node:\n\n```js\nimport { text } from 'skatejs-dom-diff';\n\nconst vText = text('my text node');\n```\n\n### `toDom()`\n\nConvers a virtual tree to a *real* DOM tree, event listeners and all:\n\n```js\nimport { toDom } from 'skatejs-dom-diff';\n\nconst vdom = \u003cp\u003eI will soon be real!\u003c/p\u003e\nconst dom = toDom(vdom);\n\n// \u003cp\u003eI will soon be real!\u003c/p\u003e\nconsole.log(dom.outerHTML);\n```\n\n### `toVdom()`\n\nConverts a real DOM tree into a virtual tree. It only copies over attributes. Event listeners can't be copied because the standard DOM APIs don't provide a way to get bound listeners.\n\n*Properties currently aren't copied either, but is being worked on.*\n\n```js\nimport { toVdom } from 'skatejs-dom-diff';\n\nconst dom = document.createElement('p');\ndom.textContent = 'I will soon be fake!';\n\nconst vdom = toVdom(dom);\n```\n\n### `types`\n\nThe types of patches that can occur. Currently these are:\n\n```js\nimport { types } from 'skatejs-dom-diff';\n\nconst {\n  APPEND_CHILD,\n  REMOVE_CHILD,\n  REMOVE_ATTRIBUTE,\n  REPLACE_CHILD,\n  SET_ATTRIBUTE,\n  SET_EVENT,\n  SET_PROPERTY,\n  TEXT_CONTENT\n} = types;\n```\n\n### Web workers\n\nYou can tell the differ to do its work in a web worker simply by passing a `done` callback option to any of the three major entry functions (`diff()`, `merge()`, `render()`).\n\n#### `diff(source, target, options)`\n\nIn the case of `diff()`, it's called once the diffing algorithm has finished in the worker and passed the `instructions`. The patch `instructions` are the only argument passed into the callback.\n\n```js\n/** @jsx h */\nimport { h, diff } from 'skatejs-dom-diff';\n\nfunction done (instructions) {\n  patch(instructions);\n}\ndiff(\u003cp\u003esource\u003c/p\u003e, \u003cp\u003etarget\u003c/p\u003e, { done });\n```\n\n#### `merge(source, target, options)`\n\nFor `done()`, it's passed in the same exact way. The only difference is that it's called after the patch is performed but it's still passed the instructions that were performed by the patch algorithm.\n\n```js\n/** @jsx h */\nimport { h, merge } from 'skatejs-dom-diff';\n\nfunction done (instructions) {\n  // The DOM has been updated, do what you want here.\n}\nmerge(\u003cp\u003esource\u003c/p\u003e, \u003cp\u003etarget\u003c/p\u003e, { done });\n```\n\n#### `render(source, target, options)`\n\nAnd for `render()`, it is the same as the `merge()` function. So once the vDOM is rendered and DOM is patched, `done()` is called with the instructions that were performed.\n\n```js\nimport { h, render } from 'skatejs-dom-diff';\n\nfunction done (instructions) {\n  // Renering and patching is done...\n}\nconst root = document.createElement('div');\nconst doRender = render((root) =\u003e (\n  \u003cdiv\u003e{root.test}\u003c/div\u003e\n));\n\ndiv.test = 'initial text';\ndoRender(div, done);\n\ndiv.test = 'updated text';\ndoRender(div, done);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskatejs%2Fdom-diff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskatejs%2Fdom-diff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskatejs%2Fdom-diff/lists"}