# pHTML Define [<img src="https://phtml.io/logo.svg" alt="pHTML" width="90" height="90" align="right">][phtml]

[![NPM Version][npm-img]][npm-url]
[![Build Status][cli-img]][cli-url]
[![Support Chat][git-img]][git-url]

[pHTML Define] lets you use custom defined elements in HTML.

```html
<!-- definitions.html -->

<define tag="pricing-tier">
  <header>
    <h1>$<slot name="price" /></h1>
    <h2><slot name="name" /></h2>
  </header>
  <div class="features">
    <slot name="features" />
  </div>
</define>

<!-- index.html -->

<link rel="html" href="definitions.html" />
<pricing-tier slot-name="Basic" class="red">
  <slot name="price">10</slot>
  <ul slot="features">
    <li>Unlimited foo</li>
  </ul>
</pricing-tier>

<!-- becomes -->

<header class="red">
  <h1>$10</h1>
  <h2>Basic</h2>
</header>
<div class="features red">
  <ul>
    <li>Unlimited foo</li>
  </ul>
</div>
```

> Note: classes assigned to the custom element are passed on to all top level children in the element definition.

Definition elements (`<define>`) can exist on the same page they are being
referenced. Definition imports (`<link rel="html" href>`) can reference real URLs.

### Slots

Slots are dynamically replaced elements and attribute values.

Within `<define>` elements, slots can referenced as elements or attribute
values. A `<slot>` element identifies its replacement with a `name` attribute —
e.g `<slot name="some-id" />` — while a slot attribute value identifies its
replacement with a dollar sign (`$`), wrapping curly braces (`{}`), and a
`slot` prefix — e.g. `${slot-some-id}`.

```html
<!-- a slot element referencing "price" -->
<slot name="price" />

<!-- a slot element referencing "price" with a fallback value of "0" -->
<slot name="price">0</slot>
```

```html
<!-- a slot attribute value referencing "src" -->
<img src="images/${slot-src}">

<!-- a slot attribute value referencing "src" with a fallback value of "default.jpg" -->
<img src="images/${slot-src,default.jpg}">
```

Within custom elements, slots are populated by element or attribute.

```html
<!-- populate a slot named "src" with image.jpg -->
<x-image slot-src="image.jpg" />
```

```html
<!-- populate a slot named "src" with image.jpg -->
<slot name="src">image.jpg</slot>
```

```html
<!-- populate a slot named "features" with <p>I will run</p> -->
<p slot="features">I will run</p>
```

## Usage

Add [pHTML Define] to your project:

```bash
npm install @phtml/define --save-dev
```

Use [pHTML Define] to process your HTML:

```js
const phtmlDefine = require('@phtml/define');

phtmlDefine.process(YOUR_HTML /*, processOptions, pluginOptions */);
```

Or use it as a [pHTML] plugin:

```js
const phtml = require('phtml');
const phtmlDefine = require('@phtml/define');

phtml([
  phtmlDefine(/* pluginOptions */)
]).process(YOUR_HTML /*, processOptions */);
```

[pHTML Define] runs in all Node environments, with special instructions for:

| [Node](INSTALL.md#node) | [CLI](INSTALL.md#phtml-cli) | [Eleventy](INSTALL.md#eleventy) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) |
| --- | --- | --- | --- | --- |

## Options

### preserve

The `preserve` option determines whether all custom element containers should remain. By default, custom element containers are not preserve. However when
custom elements are preserved, their original children are moved into a
`<template>` element.

```js
// preserve all custom elements
phtmlInclude({ preserve: true });
```

```html
<link rel="html" href="definitions.html" />
<pricing-tier slot-name="Basic">
  <slot name="price">10</slot>
  <ul slot="features">
    <li>Unlimited foo</li>
  </ul>
</pricing-tier>

<!-- becomes -->

<link rel="html" href="definitions.html" />
<pricing-tier slot-name="Basic">
  <template>
    <slot name="price">10</slot>
    <ul slot="features">
      <li>Unlimited foo</li>
    </ul>
  </template>
  <header>
    <h1>$10</h1>
    <h2>Basic</h2>
  </header>
  <div class="features">
    <ul>
      <li>Unlimited foo</li>
    </ul>
  </div>
</pricing-tier>
```

### cwd

The `cwd` option defines and overrides the current working directory of
`<link rel="html" href>`.

```js
// resolve all relative html links to /some/absolute/path
phtmlInclude({ cwd: '/some/absolute/path' });
```

### transformSlots

Custom elements, that populate slots of a parent custom element, are not replaced with their defined custom element templates.

`transformSlots` enables this nested replacement.

```js
phtmlInclude({ transformSlots: true });
```

```html
<!-- definitions.html -->

<define tag="pricing-tier">
  <header>
    <h1>$<slot name="price" /></h1>
    <h2><slot name="name" /></h2>
  </header>
  <div class="features">
    <slot name="features" />
  </div>
</define>

<define tag="call-to-action">
  <button class="call-to-action">
    <slot name="text">Click Me</slot>
  </button>
</define>

<!-- index.html -->

<link rel="html" href="definitions.html" />
<pricing-tier slot-name="Basic">
  <slot name="price">10</slot>
  <div slot="features">
    <ul>
      <li>Unlimited foo</li>
    </ul>
    <call-to-action slot-text="Buy now"></call-to-action>
  </div>
</pricing-tier>

<!-- becomes -->

<header>
  <h1>$10</h1>
  <h2>Basic</h2>
</header>
<div class="features">
  <ul>
    <li>Unlimited foo</li>
  </ul>
  <button class="call-to-action">Buy now</button>
</div>
```

[cli-img]: https://img.shields.io/travis/phtmlorg/phtml-define.svg
[cli-url]: https://travis-ci.org/phtmlorg/phtml-define
[git-img]: https://img.shields.io/badge/support-chat-blue.svg
[git-url]: https://gitter.im/phtmlorg/phtml
[npm-img]: https://img.shields.io/npm/v/@phtml/define.svg
[npm-url]: https://www.npmjs.com/package/@phtml/define

[pHTML]: https://github.com/phtmlorg/phtml
[pHTML Define]: https://github.com/phtmlorg/phtml-define
