# TemplateTemplate

**A very small JavaScript `<template>` manipulation library.**

[![npm](https://img.shields.io/npm/v/@jgarber/templatetemplate.svg?logo=npm&style=for-the-badge)](https://www.npmjs.com/package/@jgarber/templatetemplate)
[![Downloads](https://img.shields.io/npm/dt/@jgarber/templatetemplate.svg?logo=npm&style=for-the-badge)](https://www.npmjs.com/package/@jgarber/templatetemplate)

> [!NOTE]
> TemplateTemplate is feature complete and will only be updated to address bugs or security issues.

### Key Features

- Uses established Web standards (e.g. `<template>`, `document.querySelector`)
- Dependency-free
- JavaScript module (ESM)

## Getting TemplateTemplate

You've got a couple options for adding TemplateTemplate to your project:

- [Download a release](https://codeberg.org/jgarber/TemplateTemplate/releases) from Codeberg and do it yourself _(old school)_.
- Install using [npm](https://www.npmjs.com/package/@jgarber/templatetemplate): `npm install @jgarber/templatetemplate --save`
- Install using [Yarn](https://yarnpkg.com/en/package/@jgarber/templatetemplate): `yarn add @jgarber/templatetemplate`

## Usage

TemplateTemplate takes two arguments: a reference to a `<template>` element and an object of `insertions` defining the content to insert into the `<template>`.

### Basic Example

A basic example, inserting a row into a `<table>`:

```html
<table id="projects">
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Author</th>
      <th scope="col">URL</th>
      <th scope="col">Languages</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>

<template id="row-template">
  <tr>
    <th class="name" scope="row"></th>
    <td class="author"></td>
    <td class="url"></td>
    <td class="languages"></td>
  </tr>
</template>

<script type="module">
  import TemplateTemplate from "@jgarber/templatetemplate";

  const tbody = document.querySelector("#projects tbody");

  const emptyTemplate = document.querySelector("#row-template");

  const insertions = {
    ".name": "TemplateTemplate",
    ".author": "Jason Garber",
    ".url": "https://codeberg.org/jgarber/TemplateTemplate",
    ".languages": "JavaScript",
  };

  const renderedTemplate = TemplateTemplate(emptyTemplate, insertions);

  tbody.appendChild(renderedTemplate);
</script>
```

In the example above, a reference to the `<template>` element is passed to TemplateTemplate using [`document.querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). The `insertions` argument an object whose keys (e.g. `'.name'`) are valid [CSS selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) and whose values (e.g. `'TemplateTemplate'`) are strings of text to insert into the selected node.

### Advanced Example

A more complex example, inserting a row into a `<table>` with different types of insertions.

```html
<table id="projects">
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Author</th>
      <th scope="col">URL</th>
      <th scope="col">Languages</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>

<template id="row-template">
  <tr>
    <th class="name" scope="row"></th>
    <td class="author"></td>
    <td class="url"></td>
    <td class="languages"></td>
  </tr>
</template>

<template id="anchor-template">
  <a></a>
</template>

<script type="module">
  import TemplateTemplate from "@jgarber/templatetemplate";

  const tbody = document.querySelector("#projects tbody");

  const anchor = document.createElement("a");

  anchor.setAttribute("href", "https://sixtwothree.org");
  anchor.textContent = "Jason Garber";

  tbody.appendChild(
    TemplateTemplate("#row-template", {
      "tr": [null, {
        "class": "project",
        "id": "project-cashcash",
      }],
      "th": "CashCash",
      "th + td": anchor,
      ".url": ["https://codeberg.org/jgarber/CashCash", {
        "style": "font-style: italic;",
      }],
      "td:last-child": TemplateTemplate("#anchor-template", {
        "a": ["JavaScript", {
          "href": "https://codeberg.org/explore/repos?q=javascript&topic=1",
          "target": "_blank",
        }],
      }),
    }),
  );
</script>
```

The example above demonstrates a handful of additional features that you may find useful. Let's break it down with a commented version of the most interesting bits:

```js
// The first argument to TemplateTemplate may also be a valid CSS selector.
TemplateTemplate("#row-template", {
  // When an array is passed as a value, TemplateTemplate will use the first
  // index in the array as the `textContent` for the node. If this value is
  // `null`, TemplateTemplate skips setting the node's `textContent`.
  //
  // The second index is an object whose properties are added to the node as
  // HTML attributes.
  "tr": [null, {
    "class": 'project',
    "id": 'project-cashcash',
  }],

  "th": 'CashCash',

  // TemplateTemplate will use `appendChild` when given an instance of a
  // `DocumentFragment` or an `HTMLElement`.
  "th + td": anchor,

  ".url": ["https://codeberg.org/jgarber/CashCash", {
    "style": "font-weight: bold;",
  }],

  // TemplateTemplate may also be used to generate content from another
  // `<template>` and reuse it on the fly!
  "td:last-child": TemplateTemplate("#anchor-template", {
    "a": ["JavaScript", {
      "href": "https://codeberg.org/explore/repos?q=javascript&topic=1",
      "target": "_blank",
    }],
  }),
})
```

### Examples

For a full-featured TemplateTemplate demonstration, check out [the example file](https://codeberg.org/jgarber/TemplateTemplate/src/branch/main/example/index.html).

## Browser Support

**TemplateTemplate works in modern browsers.** The library makes use of several new(ish) JavaScript features and, in an effort to remain as lightweight and dependency-free as possible, leaves it up to you to choose whether or not to polyfill features for older browsers.

## Acknowledgments

TemplateTemplate is written and maintained by [Jason Garber](https://sixtwothree.org) and is another in a growing collection of small, curiously-named JavaScript utilities:

- [CashCash](https://codeberg.org/jgarber/CashCash), a very small DOM library inspired by [jQuery](https://jquery.com).
- [RadioRadio](https://codeberg.org/jgarber/RadioRadio), a very small [PubSub](https://en.wikipedia.org/wiki/Publish–subscribe_pattern) library.
- [RouterRouter](https://codeberg.org/jgarber/RouterRouter), a very small routing library extracted from [Backbone's Router](http://backbonejs.org/docs/backbone.html#section-185).

## License

TemplateTemplate is freely available under the [MIT License](https://opensource.org/licenses/MIT). Use it, learn from it, fork it, improve it, change it, tailor it to your needs.
