This project is part of the
@thi.ng/umbrella monorepo.
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:
Feature | Example and HTML equivalent/result | hiccup | hdom | rdom |
---|
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
ALPHA - bleeding edge / work-in-progress
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!
Related packages
Installation
yarn add @thi.ng/hiccup-html
// ES module
<script type="module" src="https://unpkg.com/@thi.ng/hiccup-html?module" crossorigin></script>
// UMD
<script src="https://unpkg.com/@thi.ng/hiccup-html/lib/index.umd.js" crossorigin></script>
Package sizes (gzipped, pre-treeshake): ESM: 1.44 KB / CJS: 1.85 KB / UMD: 1.75 KB
Dependencies
Usage examples
Several demos in this repo's
/examples
directory are using this package.
A selection:
Screenshot | Description | Live demo | Source |
---|
| Parser grammar livecoding editor/playground & codegen | Demo | Source |
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";
interface MyAttribs extends Attribs {
class: AttribVal<string>;
width: AttribVal<number>;
height: AttribVal<number>;
}
const el = defElement<Partial<MyAttribs>, never>(
"tag",
{ width: 100, height: 100 }
);
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.
const el = defElement<any>("a");
Call | Result |
---|
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"] |
const el = defElement<any>("a", { b: 1 });
Call | Result |
---|
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
Karsten Schmidt
License
© 2020 Karsten Schmidt // Apache Software License 2.0