npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@prsd/aitch

v1.0.0-beta.4

Published

HTML templating in JavaScript

Downloads

2

Readme

aitch

Easily create HTML templates in pure JavaScript:

import { h } from '@prsd/aitch';

const nameInput = h`<input type="text" name="name">`;
const onclick = (e) => {
  e.preventDefault();
  const name = nameInput.value;
  // process form data...
};
const form = h`
  <form>
    Name ${nameInput}
    <button type="submit" ${{ onclick }}>
      Submit
    </button>
  </form>
`;
document.body.append(form);

It's just template literals and a tag function so that we can assign values other than strings (i.e. event handlers) from within the template itself.

Motivation

JavaScript needs an HTML templating language that's:

  • Low maintenance
    • This package does not introduce a new language for creating HTML. As such, there's very little to maintain outside of bugs, breaking changes introduced by JavaScript or HTML (which is very rare).
  • Focused
    • It's designed to build HTML templates in JavaScript. State management, routing, etc. is not within the scope of this package.
  • Lightweight
    • The tag function, h, is ~1.4kB.

All JavaScript packages are required by law to make claims about how fast they are. aitch's top speed is 25 salmon per second (sm/s). aitch updates the DOM with the grace of a drowning seagull.

Installation

npm install @prsd/aitch

Guide

  • h()
    • Create HTML in JavaScript.
  • repeat()
    • Create repeating HTML elements.
  • style()
    • Create CSS styles in JavaScript.

h()

Create HTML in JavaScript.

If you use VS Code, you could add HTML syntax highlighting with a plugin like es6-string-html.

import { h } from '@prsd/aitch';

// This will create a single input node.
const input = h`<input type="text" name="firstName">`;

// A fragment is created automatically if there's more than one root node.
const formBody = h`
  First name: <input type="text" name="firstName">
  Last name: <input type="text" name="lastName">
  <button>Submit</button>
`;

// You can compose templates from other nodes.
const firstNameInput = h`<input type="text" name="firstName">`;
const ageInput = h`<input type="number" name="age">`;
const submitBtn = h`<button type="submit">Submit</button>`;
const formBody = h`
  First name: ${firstNameInput}
  Age: ${ageInput}
  ${submitBtn}
`;
const form = h`<form>${formBody}</form>`;

// You can interpolate strings, numbers, and booleans. Numbers and booleans are
// converted into strings.
const isHidden = () => true;
const ariaLevel = 5;
const ariaDescription = 'A container that displays...';
const div = h`
  <div
    aria-level="${ariaLevel}"
    aria-hidden="${isHidden()}"
    aria-description="${ariaDescription}"
  >
    Lorem ipsum...
  </div>
`;

// You can interpolate more complex values like event handlers with the use of
// a plain object.
const firstNameInput = h`<input type="text" name="firstName">`;
const ageInput = h`<input type="number" name="age">`;
const submitBtn = h`<button type="submit">Submit</button>`;
const onsubmit = (e) => {
  e.preventDefault();
  /* Does something... */
};
const form = h`
  <form ${{ onsubmit }}>
    First name: ${firstNameInput}
    Age: ${ageInput}
    ${submitBtn}    
  </form>
`;

// You can also interpolate inline styles, data attributes, and obtain a
// reference to the node from within the template using a plain object too.
// Please note that:
// (1) All inline styles declared within the "style" must be in camelCase.
// (2) All data attributes declared within the "dataset" property must be in
//     camelCase.
//     - E.g. dataset: { customData: '123' } = 'data-custom-data="123"'
// (3) "$ref" accepts a callback that receives a reference to the node. You can
//     use this, for example, to obtain a reference of the node, perform more
//     complex tasks with the node, etc.
// (4) All other properties in an object are assigned based on:
//     - (a) If the following is true "property in node", then the property is
//           assigned like this: "node[property] = value"
//           This is how event handlers are assigned.
//     - (b) If (a) is not true, then the property is assigned like this:
//           "node.setAttribute(property, value)"

let btn = null; // Gets assigned in using "$ref" below.
const form = h`
  <form>
    Email: <input type="text">
    <button ${{
      onclick: (e) => e.preventDefault(),
      style: {
        padding: '10px',
        fontFamily: '"Goudy Bookletter 1911", sans-serif',
      },
      dataset: {
        test: 'submitBtn',
        customData: '123',
      },
      $ref: (el) => (btn = el),
    }}>
      Submit
    </button>
  </form>
`;

repeat()

Create repeating HTML elements.

import { h, repeat } from '@prsd/aitch';

const peopleContainer = document.querySelector('#peopleContainer');
const people = [
  {
    id: 'A-01',
    name: 'John',
  },
  {
    id: 'Q-22',
    name: 'Michael',
  },
];
const renderPeople = () => {
  repeat({
    // Required: Container that houses the items.
    container: peopleContainer,
    // Required: Items to render. Supported types:
    // (1) Array
    // (2) Set
    // (3) Map
    // (4) Plain object.
    items: people,
    // Required: Callback that generates the element node for each item.
    element: ({ key, item: { id, name }, index }) => {
      return h`<p>${id}<br>${name}</p>`;
    },
    // Optional: Callback that is activated on each rendered element. This can
    // be used to perform more complex tasks with each rendered element.
    ref: ({ key, item, index, element }) => {},
    // Optional (but recommended to set!): The value returned by this callback
    // will be used to uniquely identify each element node.
    //
    // If this is not set, then the following will be used as keys:
    // (1) Arrays  : array indices
    // (2) Sets    : order of properties (effectively like array indices)
    // (3) Maps    : map keys
    // (4) Objects : object keys
    //
    // The value returned by this callback must be unique!
    // If (1) or (2) is used, then we highly recommended setting this callback
    // as array and/or set indices do not make good keys.
    key: ({ key, item, index }) => item.id,
    // Optional: Name of the attribute for the key that would be applied on
    // each element. If not set, the default is "data-h-repeat-key".
    keyName: 'data-key',
  });
};

// Render the list of people.
renderPeople();

// Some event happens and the "people" array is updated.
people.splice(0, 1);
people.push({ id: 'X-30', name: 'Josephine' });

// Call this again to update the DOM.
renderPeople();

style()

Create CSS styles in JavaScript.

import { style } from '@prsd/aitch';

const selector = 'div:hover';
const style = document.createElement('style');
style.innerHTML = style({
  p: {
    fontSize: '10px',
    fontWeight: 'bold',
  },
  'p > button': {
    color: 'blue',
  },
  [selector]: {
    color: 'yellow',
  },
  [`
    p > button,
    div > span
  `]: {
    display: 'absolute',
  },
  '@media (height: 360px)': {
    div: {
      fontSize: '10px',
    },
    p: {
      display: 'flex',
      flexDirection: 'column',
      fontSize: '10px',
    },
  },
  '@keyframes slideIn': {
    from: {
      transform: 'translateX(0%)',
    },
    to: {
      transform: 'translateX(100%)',
    },
  },
});

document.head.appendChild(style);