Palette
    Preparing search index...

    Palette Templates use standard HTML <template> elements as their source while compiling into an efficient, reactive Template instance.

    The templating language for Palette is HTML. In fact, you can just use <template> tags in your HTML and reference them when defining Components if you prefer. It's pretty clean!

    <template id="counting-button-template">
    <button id="btn">
    <span ::swap="$count"></span>
    </button>
    </template>
    class CountingButton extends Component {
    static template = document.getElementById("counting-button-template");
    }

    But if you want a little more oomph, you can use the html template string helper to create template elements on the fly with a little bit of added sugar:

    import { html } from "@rusticarcade/palette";

    const template = html`
    <button id="btn">
    ${"$count"}
    </button>
    `;

    When using the html helper, any string inside of an interpolated value is converted into a placeholder tag with a ::swap directive (more on that soon.)

    Additionally, you can reference previously defined Palette Components by value in templates to ensure their correct html tag is used. Great for structured apps importing other components:

    import { html } from "@rusticarcade/palette";
    import { UserProfile } from "#components";

    const template = html`
    <${UserProfile} :user-id="*user.id"></${UserProfile}>
    `;

    Templates use custom HTML attribute directives prefixed with one or two colon characters (:) to describe how the template should render with data.

    The values of these directives must be a Notation, which is a string that describes what value to use in its place when the template renders.

    Notations always begin with a special character, followed by a dot-separated accessor path.

    There are four types of Notations, based on where you want to pull data from:

    Notation Prefix Data Target Example
    @ Host element attributes @class, @content
    $ Reactive component state $hidden, $user.name
    * Computed properties *items.2.done, *classname
    # List item context #id, #message.content

    This is a one-way binding, in that the Templating system will take the current value of the notation and use it as the value for the target attribute or directive. Bound attributes to not update automatically from user input.

    Here's an example of binding a reactive state value to the "title" attribute of an element:

    <a href="..." :title="$linkTitle">Click me!</a>
    

    If our component then looks like...

    define("example-component", {
    initialState = {
    linkTitle: "I'm the link title!",
    };
    });

    Then the rendered template content would be...

    <a href="..." title="I'm the link title!">Click me!</a>
    

    Whenever the Component updates it's state, the template will automatically update with the latest values.

    In addition to the :attribute binding syntax, Palette supports several special directives for more specific use cases:

    Directive Use Example
    ::swap Swap the element for the target value <span ::swap="$content" />
    ::each Render for each item in a list <li ::each="*items" />
    ::key Define a key for list items <li ::each="*items" ::key="#id" />
    ::tag Swap the tagname of this element <h1 ::tag="*tagname">Title</h1>
    ::if Conditional rendering <div ::if="*visible"></div>
    ::else-if Conditional rendering branch <div ::else-if="@something"></div>
    ::else Conditional fallback branch <div ::else></div>

    Conditional rendering in Palette templates use the ::if, ::else-if, and ::else directives.

    Both ::if and ::else-if must be provided a notation which is evaluated to determine which conditional branch to display. ::else is a boolean attribute.

    Elemnts in a conditional with multiple branches must be immediate siblings, and must begin with an ::if, followed by zero or more ::else-if elements, and finally zero or one ::else

    <div ::if="*loggedIn" class="user-menu">
    <p>Welcome, <span ::swap="$username" />!</p>
    </div>
    <div ::else-if="*isGuest" class="guest-menu">
    <p>Welcome, guest!</p>
    </div>
    <div ::else class="register-menu">
    <a href="...">Register</a>
    </div>

    Using ::swap="<notation>" causes the element with the directive to be replaced with the value of the notation.

    Strings, numbers, and booleans are cast to strings and rendered as text nodes.

    HTMLElements are cloned and adopted to the DOM.

    null and undefined render as an HTML comment.

    Other values are unsupported.

    define("example-component", {
    template: html`
    <div>
    The current time is <span ::swap="*time"></span>
    </div>
    `,

    computedProperties = {
    time() {
    return new Date().toISOString(),
    }
    }
    })

    Using ::each="<notation>" allows for iterating over a list of data. The notation must resolve to a value that is an array of objects.

    Properties on the array items can be accessed with the # notation prefix.

    Along with ::each, you must specify a ::key directive. This directive must contain a notation which resolves to a unique value for each element in the list.

    Typically, the ::key will be something like #id, using a property called id on the list item as the key.

    class Example extends Component {
    static template = html`
    <ul>
    <li ::each="*items" ::key="#id">
    <span>The sky is ${"#color"}</span>
    </li>
    </ul>
    `;

    computedProperties = {
    items: [
    {
    id: 1,
    color: "red",
    },
    {
    id: 2,
    color: "blue",
    }
    ]
    }
    }

    Pretty simple: it just swaps out the html tag on the element with the directive.

    It retains all child contents, but it does replace the target element itself.

    describe("example-component", {
    template: html`
    <h1 ::tag="*tag">Dynamic Heading!</h1>
    `,

    computedProperties() {
    const headingLevel = this.getAttribute("level", 1);

    return {
    tag: `h${headingLevel}`
    }
    }
    })