@thi.ng/hiccup-html

@thi.ng/hiccup-html

npm versionnpm downloads Mastodon Follow

[!NOTE] This is one of 190 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.

🚀 Please help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️

About

100+ type-checked HTML5 element functions for @thi.ng/hiccup related infrastructure.

The following type-checked factory functions are provided so far and in most cases include specialized type definitions for element-specific attributes, incl. enumerated attrib values (where applicable/useful) and all 420+ CSS property names (for use with the style attrib). See type definitions in api.ts and defElement() below for more details.

Supported elements

Head / metadata

Source

base, head, link, linkCSS, meta, metaReferrer, metaRefresh, metaRobots, metaUTF8, metaViewport, metaXUA, script, style, title

Sections

Source

address, article, aside, body, footer, h1..h6, header, hgroup, html, main, nav, noscript, section

Text content

Source

blockquote, div, figure, figcaption, hr, iframe, para, pre

Lists

Source

datalist, dd, dl, dt, li, ol, ul

Tables

Source

caption, col, colgroup, table, tbody, td, tfoot, th, thead, tr

Inline

Source

abbr, anchor, br, cite, code, data, del, em, i, ins, kbd, mark, quote, small, span, strong, sub, sup, time

Forms / inputs

Source

button, checkbox, fieldset, form, inputColor, inputFile, inputNumber, inputPass, inputRange, inputSearch, inputText, label, legend, meter, option, optGroup, progress, radio, select, textArea

Media

Source

audio, canvas, img, picture, source, video

Compatibility

The hiccup syntax is (by design) merely a convention and specific feature support and interpretation is down to the actual tooling used.

Whilst not a direct aspect or feature of this package, the type definitions for element attributes defined here allow certain constructs which are only supported by some hiccup consumers. OTOH not all of the constructs are meaningful in the different usage contexts and for most there're compatible alternative ways of expressing the same data.

The table below provides an overview of the current syntax feature support by the relevant packages consuming hiccup:

FeatureExample and HTML equivalent/resulthiccuphdomrdom
Emmet style tags["div#id.foo", {}]
<div id="id" class="foo">
class attrib as object["a.bar.baz", { class: { foo: true, bar: false }}]
<a class="baz foo">
style attrib as object["div", { style: { color: "red" }}]
<div style="color:red;">
Attrib array values["img", { srcset: ["1.jpg", "2.jpg"] }]
<img srcset="1.jpg, 2.jpg">
Data attribs as object["a", { data: { foo: 42 }}]
<a data-foo="42">
Function attrib values (1)["a", { id: () => "epoch-" + Date.now() }]
<a id="epoch-1593024083666">
IDeref attrib values (2)["div", { id: { deref() { return "foo"; }}}]
<div id="foo">

All other features not explicitly mentioned are supported by all three packages.

(1) Excluding event listener attribs, these are always function values of course, but will NOT be evaluated to obtain final attrib value

(2) The IDeref interface is implemented by various data structures in the thi.ng/umbrella eco system (most relevant: @thi.ng/rstream, @thi.ng/atom).

Status

STABLE - used in production

Search or submit any issues for this package

The current aim is not necessarily to have wrappers for each possible HTML5 element, but certainly to support the most commonly used ones. PRs welcome!

Support packages

Related packages

Installation

yarn add @thi.ng/hiccup-html

ES module import:

<script type="module" src="https://cdn.skypack.dev/@thi.ng/hiccup-html"></script>

Skypack documentation

For Node.js REPL:

const hiccupHtml = await import("@thi.ng/hiccup-html");

Package sizes (brotli'd, pre-treeshake): ESM: 1.51 KB

Dependencies

Usage examples

Several projects in this repo's /examples directory are using this package:

ScreenshotDescriptionLive demoSource
Large ASCII font text generator using @thi.ng/rdomDemoSource
Interactive & reactive image blurhash generatorDemoSource
Self-modifying, animated typographic grid with emergent complex patternsDemoSource
Probabilistic color theme generatorDemoSource
Color palette generation via dominant color extraction from uploaded imagesDemoSource
Randomized space-filling, nested grid layout generatorDemoSource
Browser REPL for a Lispy S-expression based mini languageDemoSource
Mastodon API feed reader with support for different media types, fullscreen media modal, HTML rewritingDemoSource
Basic thi.ng/meta-css usage & testbedDemoSource
Parser grammar livecoding editor/playground & codegenDemoSource
Randomized 4-point 2D color gradient image generatorDemoSource
Interactive pixel sorting tool using thi.ng/color & thi.ng/pixelDemoSource
RGB waveform image analysisDemoSource
Procedural stochastic text generation via custom DSL, parse grammar & AST transformationDemoSource
rdom drag & drop exampleDemoSource
Basic usage of the declarative rdom-forms generatorDemoSource
rstream & transducer-based FSM for converting key event sequences into high-level commandsDemoSource
rdom & hiccup-canvas interop testDemoSource
Full umbrella repo doc string search w/ paginated resultsDemoSource
Defining & using basic Web Components (with shadow DOM) via @thi.ng/rdom & @thi.ng/meta-cssDemoSource
Responsive image gallery with tag-based Jaccard similarity rankingDemoSource
Generative audio synth offline renderer and WAV file exportDemoSource
Declarative component-based system with central rstream-based pubsub event busDemoSource
Responsive & reactively computed stacked column layoutDemoSource
SVG path parsing & dynamic resamplingDemoSource
Multi-layer vectorization & dithering of bitmap imagesDemoSource
rdom & WebGL-based image channel editorDemoSource

API

Generated API docs

import { div, label, option, select } from "@thi.ng/hiccup-html";
import { $compile } from "@thi.ng/rdom";

const choices = [
["#f00", "Red"],
["#ff0", "Yellow"],
["#0f0", "Green"],
["#0ff", "Cyan"],
["#00f", "Blue"],
["#f0f", "Magenta"],
];

$compile(
div(
null,
label({ for: "colors" }, "Fave color: "),
select(
{
id: "colors",
onchange: (e) => alert((<HTMLSelectElement>e.target).value),
},
option(null, "Please choose..."),
...choices.map((x) => option({ value: x[0] }, x[1]))
)
)
).mount(document.body);

defElement

All element functions are created via the higher-order function defElement which produces the typed, variadic factories. defElement takes an element name and optional set of default attributes. It also uses generics to enforce types for the element's attributes (default: Attribs and/or children/body (default: any).

Define element with defaults:

import { defElement } from "@thi.ng/hiccup-html";

const el = defElement("tag")

Define with custom attribs & no children allowed:

import { Attribs, AttribVal, defElement } from "@thi.ng/hiccup-html";

// extend global HTML default attribs
interface MyAttribs extends Attribs {
class: AttribVal<string>;
width: AttribVal<number>;
height: AttribVal<number>;
}

// provide type constraints and default attribs
const el = defElement<Partial<MyAttribs>, never>(
"tag",
{ width: 100, height: 100 }
);

// or create new versions of existing elements with more limited
// user customization options...
const div = defElement<Partial<Pick<Attribs, "class" | "style">>>("div");

The Attribs interface provides a common, fully typed base definition of HTML attributes (incl. event listeners and enumerated attrib options) and can be found in api.ts.

The AttribVal type wrapper is used to allow for reactive attribute values (in @thi.ng/rdom) and IDeref instances when later providing attribute values to an element.

Element creation

The function returned by defElement has the following signatures:

(attribs?: Nullable<T>, ...body: B[]) => [string, Nullable<T>, ...B[]];

(emmet: string, attribs?: Nullable<T>, ...body: B[]) => [string, Nullable<T>, ...B[]];

The result of either form is a simple tuple, defining an HTML element in @thi.ng/hiccup syntax.

If the second call signature is used, the initial emmet-style string will be appended to the tag name and merely acts as syntax sugar for providing an element ID and/or CSS classes.

import { defElement } from "@thi.ng/hiccup-html";

const el = defElement<any>("a");
CallResult
el()["a", null]
el(null)["a", null]
el(null, "body")["a", null, "body"]
el({ c: 2 })["a", { c: 2 }]
el({ c: 2 }, "body")["a", { c: 2 }, "body"]
el("#id.foo")["a#id.foo", null]
el("#id.foo", { c: 2 })["a#id.foo", { c: 2 }]
el("#id.foo", { c: 2 }, "body")["a#id.foo", { c: 2 }, "body"]
el("#id.foo", null, "body")["a#id.foo", null, "body"]
import { defElement } from "@thi.ng/hiccup-html";

// with default attribs
const el = defElement<any>("a", { b: 1 });
CallResult
el()["a", { b: 1 }]
el(null)["a", { b: 1 }]
el(null, "body")["a", { b: 1 }, "body"]
el({ c: 2 })["a", { b: 1, c: 2 }]
el({ c: 2 }, "body")["a", { b: 1, c: 2 }, "body"]
el("#id.foo")["a#id.foo", { b: 1 }]
el("#id.foo", { c: 2 })["a#id.foo", { b: 1, c: 2 }]
el("#id.foo", { c: 2 }, "body")["a#id.foo", { b: 1, c: 2 }, "body"]
el("#id.foo", null, "body")["a#id.foo", { b: 1 }, "body"]

Authors

If this project contributes to an academic publication, please cite it as:

@misc{thing-hiccup-html,
title = "@thi.ng/hiccup-html",
author = "Karsten Schmidt",
note = "https://thi.ng/hiccup-html",
year = 2020
}

License

© 2020 - 2024 Karsten Schmidt // Apache License 2.0

Generated using TypeDoc