Cards with slots
{card title='Revenue'} is a PAD custom tag that writes <pad-card> with its shadow root: encapsulated styles inlined by {shadow css=}, named slots the browser fills from the light DOM - and not a line of JavaScript.
{shadow}_tags/card.pad{parms}
shadowrootmode<slot>::slotted
Live
€ 48,210
12% more than last month
Details →12,804
Most of them on a phone
Details →38
Three more than usual
Details →
Open the developer tools: each card is <pad-card> with a #shadow-root PAD wrote. The page
loads no script for it - the browser builds the root from the <template shadowrootmode>, and the
styles inside it neither leak out nor let the page's in.
How it is built
PAD, on the server the browser
<div class="grid">
{cards}
{card title=$title, tone=$tone}
<p class="stat">{$value}</p>
<p class="muted">{$note}</p>
<a slot="footer" href="?examples/cards">Details →</a>
{/card}
{/cards}
</div>
<p class="muted small" style="margin-top: 18px">
Open the developer tools: each card is <code><pad-card></code> with a <code>#shadow-root</code> PAD wrote. The page
loads no script for it - the browser builds the root from the <code><template shadowrootmode></code>, and the
styles inside it neither leak out nor let the page's in.
</p><?php
// Three cards from one custom tag: {card} writes a <pad-card> with its shadow root, the
// stylesheet inlined by {shadow css=} and named slots; the page hands it the title and the
// tone as parameters and the rest as content - the light DOM the browser slots in.
$cards = [ [ 'title' => 'Revenue', 'tone' => 'good', 'value' => '€ 48,210', 'note' => '12% more than last month' ],
[ 'title' => 'Visitors', 'tone' => 'info', 'value' => '12,804', 'note' => 'Most of them on a phone' ],
[ 'title' => 'Returns', 'tone' => 'bad', 'value' => '38', 'note' => 'Three more than usual' ] ];
?>{parms title, tone='info'}
<pad-card tone="{#tone}">
{shadow css='www:elements/card.css'}
<header part="head"><slot name="title"></slot></header>
<div class="body"><slot></slot></div>
<footer part="foot"><slot name="footer"></slot></footer>
{/shadow}
<span slot="title">{#title}</span>
@content@
</pad-card>/* The shadow root of <pad-card>, inlined into it by {shadow css=}. Nothing of the page's
stylesheet reaches in - but custom properties do, so the card follows the page's theme. */
:host {
--tone: var(--accent, #e8590c);
display: block;
border-radius: 16px;
background: var(--surface, #fff);
border: 1px solid var(--line, #ddd);
border-top: 4px solid var(--tone);
box-shadow: var(--shadow, none);
overflow: hidden;
}
:host([tone="good"]) { --tone: var(--good, #108a4a); }
:host([tone="bad"]) { --tone: var(--bad, #c93838); }
:host([tone="info"]) { --tone: var(--accent, #e8590c); }
header { padding: 14px 18px 0; font: 700 12px/1.4 system-ui, sans-serif; letter-spacing: .08em; text-transform: uppercase; color: var(--tone); }
.body { padding: 4px 18px 10px; }
footer { padding: 10px 18px; border-top: 1px solid var(--line, #ddd); font-size: 14px; }
::slotted([slot="footer"]) { color: var(--tone); font-weight: 600; text-decoration: none; }