A zero-dependency, buildless, terse, and type-safe way to write HTML in JavaScript.

Overview

hdot

A sensible way to write HTML in JavaScript.

  • Type-safe. Helps you follow the HTML spec.
  • Terse. Almost character for character with plain HTML.
  • Buildless. Runs in the browser, the server, the gym.
  • Tiny. ~900 bytes (minified and gzipped). No dependencies. Size Limit controls the size.

* not affiliated with the Hawaii Department of Transportation

Read the docs

import { h } from "hdot";

h.div(
  h.h1`hdot`,
  h.p`Type-safe HTML templates`,
  h.a.href("https://hdot.dev")`Read the docs.`
);
<div>
  <h1>hdot</h1>
  <p>Type-safe HTML templates</p>
  <a href="https://hdot.dev">Read the docs.</a>
</div>
Comments
  • Allow aria attributes

    Allow aria attributes

    Is your feature request related to a problem? Please describe. hdot should support ARIA attributes to improve accessibility of a site.

    Describe the solution you'd like ARIA Attributes should be supported similar to data attributes using camelCase.

    h.button.ariaLabel('Close`)();
    

    Describe alternatives you've considered The only workaround right now is using [aria-xyz] which is not a very nice syntax (and no TS support):

    h.button['aria-label']('Close')`button`,
    
    type: feature package: hdot 
    opened by rothsandro 5
  • feat(all): rewrite internals to use tree data structure

    feat(all): rewrite internals to use tree data structure

    This PR rewrites a good bit of the core logic.

    Before

    Before, every get on h would append to this.htmlString: string internally, and calling the resulting function would return that string:

    h.div.id("test")(
      h.p`Hello world`
    ) === `<div id="test"><p>Hello world</p></div>`
    

    After this PR

    Now, instead of passing this.htmlString around and appending to it, we pass around this.tree, which has the same type signature as https://posthtml.org/#/tree.

    Furthermore, calling the resulting function will no longer return an HTML string, but return the h instance itself. Instead, one must manually call toString on the outermost function to get an HTML string.

    h.div.id("test")(
      h.p`Hello world`
    ).toString() === `<div id="test"><p>Hello world</p></div>`
    

    Why make this change? It is more verbose.

    In the first code block, hdot functions are stringified from the inside out. h.p is converted to an HTML string, which is passed as a child to h.div. This has a major ramification: parent elements can not inspect the content of their children without complex string manipulation.

    The new logic builds one tree structure, and then only stringifies once from the top down, when the dev calls toString.

    Plugins

    This enables plugins to do a lot more. Since the tree structure is the same as postHTML's, plugins should be mostly interoperable with a few more changes. Plugins will now only run once per tree, which should be a performance boost.

    TODO: add more plugin docs

    opened by willmartian 1
  • fix(hdot): aria attributes now serialize properly

    fix(hdot): aria attributes now serialize properly

    Fixes an issue where aria attributes were not properly converting to kebab case upon serialization. Resolves #2.

    Before:

    h.div.ariaLabel("test123") === `<div arialabel="test123"></div>`
    

    Now:

    h.div.ariaLabel("test123") === `<div aria-label="test123"></div>`
    

    Unit test suite "aria attributes" was added for this change.

    opened by willmartian 1
  • feat(types): add aria attributes and refactor type gen

    feat(types): add aria attributes and refactor type gen

    This PR refactors the type generation logic found in the core package.

    Key updates:

    • Aria attributes are now recognized and do not cause a type error ( resolves #2 ). Short term work still needs to be done to add JSDoc descriptions to each attribute, and refine their value type. Less short term, it would also be nice to restrict the allowed aria attributes to those that are compatible with the role of the element (is this possible?).

    • Lerna mode was swapped to independent. This PR started out with the intention to move HTML types to their own package, and with that, I decided independent mode made a bit more sense for the repo. However, I changed my mind on splitting the types into a separate package due to some limitations with mapped types preserving JSDoc comments and tags. Ideally, I would like for more of the manual type generate to utilize TS itself over code gen, but at this point the IDE type hints are better if we are less DRY (sadly).

    • More investigation needs to be done on "convenience patterns", i.e. passing Array<string> as the value to .class(). The behavior needs to be consistent--I think one off special cases are a potential footgun and I am removing for now ( concerns #3 ). Should any of the convenience patterns be built in, or moved to a plugin? I am thinking plugins, but then, what is the best way for users to update the accepted types of the h function?

      Prior art here, but it would involve changing the api in a way that requires constructing a new instance of h before it is usable: const h = new hdot().

    opened by willmartian 1
  • Type of class attribute allows array of strings

    Type of class attribute allows array of strings

    Describe the bug The parameter type of the class attribute function accepts a string or an array of strings. But when using an array it will call .join() which results in class="one,two,three".

    class-ts

    To Reproduce Steps to reproduce the behavior:

    1. Create an element: h.p.class(['one', 'two', 'three'])('hello')
    2. Inspect the element in the DOM
    3. The classes are joined with ,
    <p class="one,two,three">hello</p>
    

    Expected behavior The classes should be joined using spaces:

    <p class="one two three">hello</p>
    

    Screenshots class-join

    Desktop (please complete the following information):

    • OS: macOS
    • Browser: Brave
    • Version: 1.36
    • Node: 16.13.0
    • Eleventy: 1.0.0

    Additional context Right now we either need to use a string or add a custom plugin:

    setPlugins(h, [
      {
        attribute: (tagName, key, args) => {
          if (key === "class" && Array.isArray(args)) {
            return [key, args.join(" ")];
          }
          return [key, args];
        },
      },
    ]);
    
    type: bug question package: hdot 
    opened by rothsandro 2
  • Add auto-generated types for valid HTML descendants

    Add auto-generated types for valid HTML descendants

    Currently, hdot does not type-check the content category of children passed to other elements. This feature needs to be added to the element types here.

    The following should cause a type error, since <link> is an empty element.

    h.link('Hello world'); 
    

    Find more info here: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories

    type: feature package: hdot 
    opened by willmartian 0
Owner
Will Martin
Open source nerd | prev core contributor at @ionic-team
Will Martin
A functional, immutable, type safe and simple dependency injection library inspired by angular.

func-di English | 简体中文 A functional, immutable, type safe and simple dependency injection library inspired by Angular. Why func-di Installation Usage

null 24 Dec 11, 2022
Zero runtime type-safe CSS in the same file as components

macaron comptime-css is now called macaron! macaron is a zero-runtime and type-safe CSS-in-JS library made with performance in mind Powered by vanilla

Mokshit Jain 205 Jan 4, 2023
A bullet journaling plugin for Obsidian that aggregates a terse stream of backlinked clippings in the footer of notes.

A plugin for Obsidian that aggregates a terse stream of backlinked clippings in the footer of notes. Intended usage pattern: (Or: How to get the most

Jens MT Gleditsch 157 Jan 4, 2023
100% type-safe query builder for node-postgres :: Generated types, call any function, tree-shakable, implicit type casts, and more

⚠️ This library is currently in alpha. Contributors wanted! tusken Postgres client from a galaxy far, far away. your database is the source-of-truth f

alloc 54 Dec 29, 2022
A fully type-safe and lightweight way of using exceptions instead of throwing errors

??️ exceptionally A fully type-safe and lightweight way of using exceptions instead of throwing errors ?? fully typesafe ?? lightweight (209 bytes) ??

Hofer Ivan 16 Jan 4, 2023
Reference for How to Write an Open Source JavaScript Library - https://egghead.io/series/how-to-write-an-open-source-javascript-library

Reference for How to Write an Open Source JavaScript Library The purpose of this document is to serve as a reference for: How to Write an Open Source

Sarbbottam Bandyopadhyay 175 Dec 24, 2022
Zero Dependency, Vanilla JavaScript Tag Editor

_____ |_ _|___ ___ ___ ___ ___ | | | .'| . | . | -_| _| |_| |__,|_ |_ |___|_| |___|___| version 0.4.4 Tagger: Zero dependenc

Jakub T. Jankiewicz 155 Nov 25, 2022
A fully type-safe and lightweight internationalization library for all your TypeScript and JavaScript projects.

?? typesafe-i18n A fully type-safe and lightweight internationalization library for all your TypeScript and JavaScript projects. Advantages ?? lightwe

Hofer Ivan 1.3k Jan 4, 2023
A lightweight Adobe Photoshop .psd/.psb file parser in typescript with zero-dependency for WebBrowser and NodeJS

@webtoon/psd A lightweight Adobe Photoshop .psd/.psb file parser in typescript with zero-dependency for WebBrowser and NodeJS Browser Support Chrome F

null 830 Jan 1, 2023
A zero-dependency, strongly-typed web framework for Bun, Node and Cloudflare workers

nbit A simple, declarative, type-safe way to build web services and REST APIs for Bun, Node and Cloudflare Workers. Examples See some quick examples b

Simon Sturmer 16 Sep 16, 2022
Dynamic, fast, accessible & zero dependency accordion for React

React Fast Accordion ⚡️ Dynamic, fast, accessible & zero dependency accordion for React How it's fast? Instead of adding event listener on all the ite

Shivam 59 Oct 8, 2022
Shifty is a tiny zero-dependency secrets generator, built for the web using TypeScript.

Shifty is a tiny zero-dependency secrets generator, built for the web using TypeScript. Installation yarn add @deepsource/shifty Usage Shifty is built

DeepSource 46 Nov 24, 2022
Jsonup - This is a zero dependency compile-time JSON parser written in TypeScript

jsonup This is a zero dependency compile-time JSON parser written in TypeScript.

TANIGUCHI Masaya 39 Dec 8, 2022
Zero dependency profanity detector.

@cnakazawa/profane Zero dependency profanity detector based on Swearjar and Profane. Note: Some examples may contain offensive language for illustrati

Christoph Nakazawa 11 Dec 28, 2022
Cloudy is a set of constructs for the AWS Cloud Development Kit that aim to improve the DX by providing a faster and type-safe code environment.

cloudy-ts These packages aren't yet published on npm. This is still highly experimental. Need to figure out a few things before releasing the first ve

Cristian Pallarés 5 Nov 3, 2022
A script that combines a folder of SVG files into a single sprites file and generates type definitions for safe usage.

remix-sprites-example A script that combines a folder of .svg files into a single sprites.svg file and type definitions for safe usage. Technical Over

Nicolas Kleiderer 19 Nov 9, 2022
Type safe library for interacting with Mindbody's Public API (v6) and Webhooks

Mindbody API Type safe library for interacting with Mindbody's Public API (v6) and Webhooks ⚠️ Read before installing This library is typed according

SplitPass 4 Dec 9, 2022
Build type-safe web apps with PureScript.

PUX Build type-safe web applications with PureScript. Documentation | Examples | Chat Pux is a PureScript library for building web applications. Inter

Alex Mingoia 567 Jun 18, 2022
Type Safe Object Notation & Validation

tson Type Safe Object Notation & Validation ?? Work in Progress, not ready for production... Features ?? Functional ?? Immutable ✅ Well tested Why? Af

null 9 Aug 10, 2022