A library: Lit
A Lit element rendered in the browser, fed by PAD through an attribute: items="{^items}" is JSON Lit reads into a property - the same data any element gets.
{^field}
LitElementstatic properties
Live
- 2019: Custom elements and shadow DOM in every browser
- 2020: Form-associated custom elements, ElementInternals
- 2023: Declarative shadow DOM - shadowrootmode - in Chrome and Safari
- 2024: Declarative shadow DOM in Firefox: everywhere
How it is built
PAD, on the server the browser
<pad-timeline items="{^items}">
<ul>{items}<li>{$year}: {$what}</li>{/items}</ul>
</pad-timeline>
<script type="module" src="{$padRoot}webcomponents/elements/timeline.js"></script><?php
// The data of the timeline: a PHP array, written into the element's items attribute as JSON
// by the ^ sigil. Lit reads the attribute into the items property (type: Array) and renders.
$items = [ [ 'year' => 2019, 'what' => 'Custom elements and shadow DOM in every browser' ],
[ 'year' => 2020, 'what' => 'Form-associated custom elements, ElementInternals' ],
[ 'year' => 2023, 'what' => 'Declarative shadow DOM - shadowrootmode - in Chrome and Safari' ],
[ 'year' => 2024, 'what' => 'Declarative shadow DOM in Firefox: everywhere' ] ];
?>// <pad-timeline>, a Lit element: rendered in the browser, fed by PAD through the items
// attribute - JSON the ^ sigil wrote, read into the items property by Lit's Array converter.
import { LitElement, html, css } from 'https://cdn.jsdelivr.net/npm/lit@3/+esm';
class PadTimeline extends LitElement {
static properties = {
items: { type: Array },
open: { state: true }
};
static styles = css`
:host { display: block; }
ol { list-style: none; margin: 0; padding: 0 0 0 22px; border-left: 2px solid var(--line, #ddd); }
li { position: relative; margin: 0 0 14px; padding: 12px 16px; border-radius: 12px; background: var(--surface-2, #f4f4f4); cursor: pointer; }
li::before { content: ''; position: absolute; left: -30px; top: 16px; width: 12px; height: 12px; border-radius: 50%; background: var(--accent, #e8590c); }
li.is-open { outline: 2px solid var(--accent, #e8590c); }
.year { font: 800 13px/1 system-ui, sans-serif; color: var(--accent, #e8590c); }
`;
constructor() {
super();
this.items = [];
this.open = -1;
}
render() {
return html`
<ol>
${this.items.map((item, at) => html`
<li class=${at === this.open ? 'is-open' : ''} @click=${() => { this.open = at === this.open ? -1 : at; }}>
<div class="year">${item.year}</div>
<div>${item.what}</div>
</li>`)}
</ol>`;
}
}
customElements.define('pad-timeline', PadTimeline);