Skip to main content
Home
Works with
This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
This package works with Browsers
JSR Score70%
Publisheda year ago (0.0.9)

Clean and performant HTML in pure JavaScript

jshtml - Clean & Performant HTML in Pure JavaScript

jshtml is a lightweight library for writing clean and performant HTML in pure JavaScript. Create HTML elements and custom components naturally using JavaScript arrays and functions, then render them to spec-compliant HTML strings or serializable JSON.

jshtml provides a JSX-like developer experience without requiring any transpilation or build tools. jshtml has no dependencies and can be used to render HTML on a server on within the browser. The following example shows how to construct and render jshtml elements:

import jshtml from "./jshtml.js";

// Define your components using regular JavaScript functions
function App() {
  const title = "My JSHTML App";
  const items = ["Apple", "Banana", "Orange"];

  // Use nested arrays to create HTML elements
  return [
    `html`,
    [`head`, [`title`, title]],
    [
      `body`,
      { class: "container" }, // Use objects for attributes
      [Header, { title }],
      [
        `main`,
        [`h2`, "Favorite Fruits"],
        [`ul`, { children: items.map((item) => [`li`, item]) }],
      ],
      [Footer, [`p`, "Visit our website for more."]],
    ],
  ];
}

// Components can accept props
function Header({ title }) {
  return [`header`, [`h1`, { class: "title" }, title]];
}

// Components can accept children
function Footer({ children }) {
  return [`footer`, [`p`, "© 2024 JSHTML"], ...children];
}

// Render to a spec-compliant HTML string
const html = jshtml.renderToHtml([App]);
console.log(html);

This will output clean, spec-compliant HTML (without any spaces or indentation):

<html>
  <head>
    <title>My JSHTML App</title>
  </head>
  <body class="container">
    <header>
      <h1 class="title">My JSHTML App</h1>
    </header>
    <main>
      <h2>Favorite Fruits</h2>
      <ul>
        <li>Apple</li>
        <li>Banana</li>
        <li>Orange</li>
      </ul>
    </main>
    <footer>
      <p>© 2024 JSHTML</p>
      <p>Visit our website for more.</p>
    </footer>
  </body>
</html>

The element can also be rendered to serializable JSON that can be edited programmatically or sent over the wire:

const json = jshtml.renderToHtml([App]);
console.log(json);

This produces the following JSON-serializable output:

[
  "html",
  ["head", ["title", "My JSHTML App"]],
  [
    "body",
    { "class": "container" },
    ["header", ["h1", { "class": "title" }, "My JSHTML App"]],
    [
      "main",
      ["h2", "Favorite Fruits"],
      [
        "ul",
        ["li", "Apple"],
        ["li", "Banana"],
        ["li", "Orange"]
      ]
    ],
    [
      "footer",
      ["p", "© 2024 JSHTML"],
      ["p", "Visit our website for more."]
    ]
  ]
]

Use jshtml in place of HTML templates (like Mustache, EJS, etc.) and JSX to construct and generate HTML within JavaScript code.

Installation & Usage

You can use jshtml by simply copying the jshtml.js file into your project. It's a single JavaScript file without any dependencies, and will not require transpilation.

You can also install from JSR it as follows:

npx jsr add @aakashns/jshtml

or

deno add jsr:@aakashns/jshtml

To use it, just import jshtml from jshtml.js:

import jshtml from "./jshtml.js";

Construct jshtml elements using arrays and functions as shown below, and render them using jshtml.renderToHtml or jshtml.renderToJson.

How to Write JSHTML

HTML Tags

HTML elements are represented as arrays where the first element is a string representing the tag name:

// Basic elements
const element1 = [
  `div`,
  "Hello world",
];

const element2 = [`br`];

const element3 = [
  `p`,
  { class: "text" },
  "Some text",
];

// Nesting elements
const element4 = [
  `div`,
  [`h1`, "Title"],
  [`p`, "Paragraph"],
];

Attributes (Props)

Attributes (also referred to as "props") can be optionally specified as an object in the second position of the array:

const element = [
  `button`,
  {
    type: "submit",
    class: "btn primary",
    disabled: true,
    "data-id": "123",
  },
  "Submit",
];

Non-string attribute values are handled as follows while rendering:

  • Boolean attributes (like disabled) will be included if set to true true, and omitted if false
  • Attributes with null and undefined values are omitted
  • Other values are automatically converted to strings and properly escaped

Children

Children can be provided in two ways:

  1. As additional array elements after the tag and props:
const element1 = [
  `div`,
  [`h1`, "Title"],
  [`p`, "First paragraph"],
  [`p`, "Second paragraph"],
];

const element2 = [
  `div`,
  { class: "container" },
  [`h1`, "Title"],
  [`p`, "First paragraph"],
  [`p`, "Second paragraph"],
];
  1. As the children prop (must be an array of elements):
[`div`, {
  class: "container",
  children: [
    [`h1`, "Title"],
    [`p`, "Paragraph"],
  ],
}];

Individual children can be:

  • Strings (automatically escaped to prevent XSS attacks)
  • Numbers (converted to strings)
  • Arrays representing jshtml elements
  • null, undefined, or false (ignored)

Components

Components are regular JavaScript functions that accept a single object containing props and children and return jshtml element:

function Button({ type = "button", onClick, children }) {
  return [
    `button`,
    {
      type,
      class: "btn",
      onclick: onClick,
    },
    ...children,
  ];
}

Once defined, they can be used in place of regular HTML tags:

// Usage
const element = [
  Button,
  {
    type: "submit",
    onClick: "handleClick()",
  },
  "Click me",
];

The syntax for defining and using components is nearly identical to the JSX syntax used by libraries like React. Use components to break your HTML page into modular, reusable pieces.

Raw HTML

For cases where you need to insert pre-formatted HTML, use the rawHtml prop:

const element = [
  `div`,
  {
    rawHtml: "<strong>Pre-formatted</strong> HTML",
  },
];

Note: Use this carefully as the content is not escaped!

Empty Tag (Fragment)

For cases where you need to create a list of elements without an outer tag, you can use the empty tag \``:

const element = [
  ``,
  [`p`, "Hello, world"],
  [`p`, "How are you today?"],
];

const html = jshtml.render(element);
// <p>Hello, world</p><p>How are you today?</p>

The above element will be rendered as two p tags witout a parent.

Rendering jshtml Elements

To HTML

Convert JSHTML elements to HTML strings:

const element = [
  `div`,
  { class: "greeting" },
  "Hello, World!",
];
const html = jshtml.renderToHtml(element);
// <div class="greeting">Hello, World!</div>

To Serializable JSON

Convert JSHTML elements to JSON-safe format (useful for sending over network):

const element = [
  `div`,
  { class: "greeting" },
  "Hello, World!",
];
const json = jshtml.renderToJson(element);
// ["div", { "class": "greeting" }, "Hello, World!"]

The output of renderToJson can be passed to renderToHtml to generate the same HTML output as the original element.

Comparison with JSX

jshtml provides a similar developer experience to JSX but with several advantages:

  • ✅ No build tools or transpilation needed
  • ✅ Works with vanilla JavaScript
  • ✅ Fully typed and predictable
  • ✅ Smaller bundle size
  • ✅ Easier to debug (just arrays and objects)
  • ✅ Can be serialized to JSON
  • ✅ Runtime validation of tags and attributes

The main difference in syntax is using arrays instead of XML-like notation:

// JSX
<div className="container">
  <h1>{title}</h1>
  <p>Content</p>
</div>;

// jshtml
[
  `div`,
  { class: "container" },
  [`h1`, title],
  [`p`, "Content"],
];

Both approaches support components, props, and children with very similar patterns, making it easy to transition between them.

NOTE: jshtml does not support state, hooks, lifecycle methods and other such features for building dynamic UIs as its primary purpose is to generate HTML strings.

Acknowledgement

jshtml borrows heavily from the work done by the late Jason Knight on a library called DOM-JON, a browser-only implementation of a similar syntax for efficient DOM manipulation in pure JavaScript.

Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@aakashns/jshtml

Import symbol

import * as jshtml from "@aakashns/jshtml";
or

Import directly with a jsr specifier

import * as jshtml from "jsr:@aakashns/jshtml";

Add Package

pnpm i jsr:@aakashns/jshtml
or (using pnpm 10.8 or older)
pnpm dlx jsr add @aakashns/jshtml

Import symbol

import * as jshtml from "@aakashns/jshtml";

Add Package

yarn add jsr:@aakashns/jshtml
or (using Yarn 4.8 or older)
yarn dlx jsr add @aakashns/jshtml

Import symbol

import * as jshtml from "@aakashns/jshtml";

Add Package

vlt install jsr:@aakashns/jshtml

Import symbol

import * as jshtml from "@aakashns/jshtml";

Add Package

npx jsr add @aakashns/jshtml

Import symbol

import * as jshtml from "@aakashns/jshtml";

Add Package

bunx jsr add @aakashns/jshtml

Import symbol

import * as jshtml from "@aakashns/jshtml";