A fully assembled demo page, featuring a tree and a gallery (with something configured in every slot)

<!DOCTYPE html>
<html lang="en">
    <title>Anura Webcomponents Example</title>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="module" src="adapters/some-adapter.js"></script>
    <script type="module" src="components/anura-components.js"></script>

<some-adapter url="https://my.server.io/api" locale="de"></some-adapter>

<div style="display: flex">
    <aside aria-label="Navigation">
        <anura-tree adapter="some-adapter" show-root="true" depth="1" root="1737" selected="1738" icon="archive" aria-live="polite"></anura-tree>
    <main aria-label="Gallery">
        <anura-counter parent="anura-gallery"></anura-counter>
        <anura-gallery adapter="some-adapter" search="anura-tree" page-size="32" aria-live="polite">
            <anura-asset slot="asset" buttons="download,checkbox,info" quick-download="1"></anura-asset>
            <anura-paginator slot="paginator" mode="auto" detect-scroll="false"></anura-paginator>
        <anura-lightbox buttons="fullscreen,sidebar,close">
            <anura-details slot="sidebar" allowlist="id,name,info_102,info_103"></anura-details>

View switcher

Offer different view components for the same content. The key here is to set the other views as disabled.

<some-adapter url="https://my.server.io/api" locale="de"></some-adapter>

<select id="demo-switcher">
    <option value="anura-gallery">Gallery</option>
    <option value="anura-table">Table</option>
    <option value="anura-map">Map</option>

<anura-gallery adapter="some-adapter" source="omitted" class="main-view"></anura-gallery>
<anura-table   adapter="some-adapter" source="omitted" class="main-view" disabled></anura-table>
<anura-map     adapter="some-adapter" source="omitted" class="main-view" disabled></anura-map>

    document.querySelector('#demo-switcher').addEventListener('change', e => {
        document.querySelectorAll('.main-view').forEach(view => view.setAttribute('disabled', ''));

Disabled components do not react to source updates (and get aria-hidden). Once re-enabled, the sources are queried again to update the content.

Content Slot (string interpolation)

anura-asset offers a content slot to put additional information, be that asset markers (aka bullets) or more text.

The following snippet demonstrates both, the span creates a file extension bullet "JPG", the p adds a description line beneath (taken from a metadata field of that name):

<anura-gallery ...>
    <anura-asset slot="asset" ...>
        <span slot="content">
            <span class="asset-marker" style="color: white; position: absolute; bottom: 37%; right: 3%; background: rgba(0, 34, 51, 0.4); padding: 2px 5px; border-radius: 2px; font-size: 0.8rem; text-transform: uppercase;">
            <p if="${asset.metadata[description].value}" class="description" style="font-size: 85%; margin: 0.25rem 0;">
                ${asset.metadata[description].name}: ${asset.metadata[description].value}

Note how you can add an if attribute to any sub-node, so that you don't get a "Description: " with no actual value to display (removes the node when empty). This yields:

screenshot of the content slot

While if simply checks if any value is present, you may also use equals and contains as conditional attributes, e.g.

<span if="${asset.metadata[copyright].value}" contains="copyrighted">
    <img src="img/copyright-symbol.svg">

Button Slots

anura-asset and anura-lightbox both offer a slot called buttons where you can place custom buttons. Let's add one for each inside of a gallery (with a simple alert()):

<anura-gallery adapter="some-adapter">
    <anura-asset slot="asset" buttons="basket,info">
        <span slot="buttons">
            <button onclick="alert('Asset '+this.value)" title="demo" style="background: none; border: none; padding: 0">
                <anura-icon icon="alert-triangle"></anura-icon>
<anura-lightbox buttons="basket,sidebar,close">
    <span slot="buttons">
        <button onclick="alert('Lightbox asset '+this.value)" title="demo" style="background: none; border: none; padding: 0; margin: 1.5rem">
            <anura-icon icon="alert-triangle"></anura-icon>

Note how the value of the click event provides you the ID of the current asset. We'd also advise to use an anura-icon inside for consistency.

Variable Scopes

When changing a variable, it may be necessary to inform more than one party. This is a limitation of parts and can be addressed by telling both components (in this case anura-gallery and the anura-asset inside of it):

anura-gallery, anura-gallery::part(anura-asset) {
    --asset-width: 15rem;
    --asset-height: 15rem;

Variables + Parts + String Interpolation

To demonstrate what you can achieve through variables, parts and string interpolation, suppose we want a gallery with wide assets, in order to show more details upfront. In other words, we want to go from this:

screenshot of the regular gallery

... to this:

screenshot of a wide gallery

Which we can easily achieve using 2 variables, 3 parts and 4 table rows:

    <script type="module" src="components/..."></script>
        anura-gallery, anura-gallery::part(anura-asset) {
            --asset-width: 25rem; /* change aspect ratio */
            --asset-height: 8rem;
            flex-direction: row; /* move content to the right */
        anura-gallery::part(asset-figure) {
            width: 33%; /* shrink the thumbnail */
            margin-right: 2%;
            height: 100%;
        anura-gallery::part(asset-title) {
            display: none; /* no figcaption */
    <some-adapter url="https://..." infofields="127,128,160"></some-adapter>
    <anura-gallery adapter="some-adapter" aria-live="polite">
        <anura-asset slot="asset">
            <span slot="content">
                <table style="font-size: 90%">
                        <td>${asset.name}</td><!-- interpolate ${} -->
                    <tr if="${asset.metadata[info_160].value}"> <!-- hide the row if value is empty -->
                    <tr if="${asset.metadata[info_128].value}">
                    <tr if="${asset.metadata[info_127].value}">