# @lcf.vs/dom-engine

> A composable DOM based template engine

Latest version **6.1.0** (published 2026-08-29) · MIT license · 0 weekly downloads

## Install

```sh
npm install @lcf.vs/dom-engine
pnpm add @lcf.vs/dom-engine
yarn add @lcf.vs/dom-engine
bun add @lcf.vs/dom-engine
```

## Health

**Score 60/100 (C)** — status: active.

Positive: esm support; no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no types.

## Facts

| | |
|---|---|
| Version | 6.1.0 |
| Published | 2026-08-29 |
| First published | 2020-06-22 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | ESM |
| Dependencies | 1 |
| Unpacked size | 18.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | lcf.vs |
| Maintainers | lcf.vs |
| Keywords | JavaScript, DOM, template, engine |

## Links

- npm: https://www.npmjs.com/package/@lcf.vs/dom-engine
- Repository: https://github.com/Lcfvs/dom-engine
- Homepage: https://github.com/Lcfvs/dom-engine#readme
- Issues: https://github.com/Lcfvs/dom-engine/issues
- npm.io page: https://npm.io/package/@lcf.vs/dom-engine

## Dependencies (1)

- [jsdom](https://npm.io/package/jsdom.md) ^30.0.1

## Alternatives

- [babylon](https://npm.io/package/babylon.md) — 5.1M weekly downloads
- [csscolorparser](https://npm.io/package/csscolorparser.md) — 3.7M weekly downloads
- [expr-eval-fork](https://npm.io/package/expr-eval-fork.md) — 1.5M weekly downloads
- [@leeoniya/ufuzzy](https://npm.io/package/@leeoniya/ufuzzy.md) — 247.7K weekly downloads
- [xml-parser](https://npm.io/package/xml-parser.md) — 78.4K weekly downloads

## Recent versions

- 6.1.0 (latest) — 2026-08-29
- 6.0.0 — 2026-08-29
- 5.5.4 — 2022-03-07
- 5.5.3 — 2021-10-10
- 5.5.2 — 2021-09-26
- 5.5.0 — 2021-09-24
- 5.4.1 — 2021-09-13
- 5.4.0 — 2021-09-13
- 5.3.2 — 2021-09-04
- 5.3.1 — 2021-09-04
- 5.3.0 — 2021-09-04
- 5.2.5 — 2021-09-04
- 5.2.4 — 2021-08-19
- 5.2.3 — 2021-08-12
- 5.2.2 — 2021-08-12
- … 41 more at https://npm.io/package/@lcf.vs/dom-engine/versions

## README

# @lcf.vs/dom-engine

A composable DOM based template engine


## Install

`npm i @lcf.vs/dom-engine`


## Usage


### Markers

There is 2 type of markers:

* **Required**: `{name}`
  * The value can't be nullish
* **Optional**: `{?name}`
  * If a nullish value is provided for an attribute, that attribute is removed


### Create a fragment template

```js
import { template } from '@lcf.vs/dom-engine'

const pTemplate = template(`<p class="{?classes}">{salutations} {?name}</p>`, {
  classes: null,
  salutations: null,
  name: null
})
```


### Create a fragment template, using the `source` symbol

```js
import { source } from '@lcf.vs/dom-engine'

const pTemplate = {
  [source]: '<p class="{?classes}">{salutations} {?name}</p>',
  classes: null,
  salutations: null,
  name: null
}
```

### Create a value filled node

```js
// object representing <p>hello user-name</p>
const p = {
  ...pTemplate,
  salutations: 'hello',
  name: 'user-name'
}

// object representing <p>hello</p>
const p = {
  ...pTemplate,
  salutations: 'hello'
}

// Error: missing {salutations} (on serialization)
const p = {
  ...pTemplate
}
```

### Use templates as value

```js
const taggedName = {
  [source]: '<strong>{name}</strong>',
  name: null
}

// object representing <p>hello <string>user-name</strong></p>
const p = {
  ...pTemplate,
  salutations: 'hello',
  name: {
    ...taggedName,
    name: 'user-name'
  }
}

// object representing <p>hello <strong>user-name</strong></p>
const p = {
  ...pTemplate,
  salutations: 'hello',
  name: {
    ...taggedName,
    name: 'user-name'
  }
}
```

```js
// object representing <p>hello <strong><span>user-name</span></strong></p>
const p = {
  ...pTemplate,
  salutations: 'hello',
  name: template(`<span>user-name</span>`)
}
```

```js
// object representing <p>hello <strong><span>user</span>-<span>name</span></strong></p>
const p = {
  ...pTemplate,
  salutations: 'hello',
  name: [
    template(`<span>user</span>`),
    template(`-`),
    template(`<span>name</span>`)
  ]
}
```

### Use object properties
```js
// object representing <p>hello <strong>user</strong></p>
const pTemplate = {
  [source]: '<p>{salutations} <strong>{user.name}</strong></p>',
  salutations: 'hello',
  user: {
    name: 'user'
  }
}
```


## Serialize a template

```js
import { serialize } from '@lcf.vs/dom-engine'

const p = template(`<p>user-name</p>`)
const html = await serialize(p)
```

## APIs

```js
import { template, source } from '@lcf.vs/dom-engine'

const tpl = template(html, { ...fields } = {})

// or 

const tpl = {
  [source]: html,
  ...fields
}
```

### Back-End

```js
import { load } from '@lcf.vs/dom-engine'

// loads a file with the same name than the current module,
// but with a .html extension instead of the current one
const tpl = await load(import.meta, { ...options } = {}, { ...data } = {})
```
Where the options are the **async** `readFile()` ones

```js
import { serialize } from '@lcf.vs/dom-engine'

const htmlString = await serialize(template)
```
Or
```js
import { render } from '@lcf.vs/dom-engine'

const htmlNode = render(template)
```

### Front-End

```js
import { load } from '@lcf.vs/dom-engine'

// loads a file with the same name than the current module,
// but with a .html extension instead of the current one
const tpl = await load(import.meta, { ...options } = {}, { ...data } = {})
```
Where the options are the `fetch()` ones

```js
import { serialize } from '@lcf.vs/dom-engine'

const htmlString = await serialize(template)
```
Or
```js
import { render } from '@lcf.vs/dom-engine'

const htmlNode = render(template)
```

### ServiceWorker

The engine also supports the rendering of some templates stored into a `ServiceWorker`.

To use it, you need to add the following components.

#### Into the `window` script

```js
import '@lcf.vs/dom-engine/lib/worker-client.js'
```

#### Into the `ServiceWorker` script

```js
import { load } from '@lcf.vs/dom-engine'

// loads a file with the same name than the current module,
// but with a .html extension instead of the current one
const tpl = await load(import.meta, { ...optio*ns } = {}, { ...data } = {})
```
Where the options are the `fetch()` ones

```js
import { serialize, source } from '@lcf.vs/dom-engine'

const text = 'This page is built by sw-template'

const view = {
  [source]: `<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>{text}</title>
  <script src="/main.js" type="module"></script>
</head>
<body>
  <main>
    <h1>{text}</h1>
    <a href="/">back to home</a>
  </main>
</body>
</html>`
}

const html = await serialize({
  ...view,
  text
})
```

Just note that: if the browser doesn't support the ES6 modules, into the `ServiceWorker`, you should need to bundle your code.

[A very basic demo](https://glitch.com/edit/#!/dom-engine-sw?path=sw-routes.js%3A25%3A6)


### Security

To improve your client-side security, you can add the following header on your requests (or via a `<meta>`)

`Content-Security-Policy: default-src 'none'; connect-src 'self'; script-src 'self'; style-src 'self'; require-trusted-types-for 'script'; trusted-types dom-engine`

Since the templates filling is intended to avoid XSS injections, by design, you need to be sure about your templates.

Of course, it's just a **minimal** one, you can adapt it on your needs.


## License

[MIT](./LICENSE)

---
_Source: https://npm.io/package/@lcf.vs/dom-engine · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
