Layout
The layout components frame a page: a container, a grid, a page header, a side nav and a top nav. They are the pieces the docs site itself is built from, so the closing section shows them assembled. Each takes the shared props plus those listed here.
`PinkContainer` Copy link
A <div class="container"> — pink's centered, max-width content column. Takes is for another root (el('footer'), el('main')).
`PinkGridBox` Copy link
A responsive card grid; the root is a <ul class="grid-box"> (is to change it) and the children are its items. The props map onto the grid's variables and are omitted from the style when unset:
Prop | Effect |
|---|---|
| A number renders |
| The minimum item width, and its override at small widths. |
| The gap. |
|
|
import { component, el } from '@loom-js/core';
import { PinkCard, PinkGridBox } from '@loom-js/pink';
export const Features = component<{ features: string[] }>(
(html, { features }) => html`
<${PinkGridBox} gridGap="1rem" gridItemSize="16rem">
${features.map((feature) =>
PinkCard({ children: feature, is: el('li') })
)}
</> ` );`PinkGridHeader` Copy link
A page header on pink's header grid. Content arrives through named slots, not props: col1 is the leading column (the title), col2–col4 render in a trailing cluster that collapses on mobile. Slotted content renders as authored, so place the grid classes (grid-header-col-1 … -4) on your own elements.
import { component } from '@loom-js/core';
import { PinkButton, PinkGridHeader } from '@loom-js/pink';
export const DatabasesHeader = component(
(html) => html`
<${PinkGridHeader}>
<h2 slot="col1" class="heading-level-5 grid-header-col-1">Databases</h2> <${PinkButton} slot="col2" className="grid-header-col-2" icon="icon-plus">
Create database </> </> ` );`PinkSideNav` Copy link
The side navigation: a <nav class="side-nav"> (is to change it) with a main area and an optional bottom section. The main area has two forms:
topLinkProps— one flat list of links, each aPinkDropListitem (children,href,icon,isSelected,onClick).top— arbitrary content, for a nav with several labelled sections or collapsible groups. Takes precedence overtopLinkProps.
import { component, route } from '@loom-js/core';
import { PinkSideNav } from '@loom-js/pink';
export const AppNav = component<{ current: string }>(
(html, { current }) => html`
<${PinkSideNav}
topLinkProps=${[
{ children: 'Home', href: '/', icon: 'icon-home', isSelected: current === '/', onClick: route },
{ children: 'Docs', href: '/docs', icon: 'icon-document', isSelected: current === '/docs', onClick: route }
]}
/> ` );The docs site's nav is the top form: a PinkDropList whose items are PinkCollapsible groups, the active topic's group rendered open.
`PinkTopNav` Copy link
A horizontal <nav> of links from items — each children, href, target, className, attrs and an optional onClick. The nav-level onClick and on apply to every item that supplies none of its own, so one route handler covers the internal links while an external item opts out with its own handler:
import { component, route } from '@loom-js/core';
import { PinkTopNav } from '@loom-js/pink';
export const SiteNav = component(
(html) => html`
<${PinkTopNav}
items=${[
{ children: 'Docs', href: '/docs' },
{ children: 'Benchmarks', href: '/benchmarks' },
{ children: 'GitHub', href: 'https://github.com/claudio-darkkenergy/loom-js', onClick: () => {}, target: '_blank' }
]}
onClick=${route}
/> ` );Putting a page together Copy link
The docs site's shell is these five in one template: a PinkGridHeader with the brand in col1 and a PinkTopNav in col2, a <main> whose docs pages render a PinkSideNav beside the content, and a PinkContainer rendered as the <footer>:
import { component, el, route } from '@loom-js/core';
import { PinkContainer, PinkGridHeader, PinkTopNav } from '@loom-js/pink';
export const PageLayout = component(
(html, { children }) => html`
<div id="layout" class="body-text-1"> <${PinkGridHeader} className="u-padding-16">
<a slot="col1" class="grid-header-col-1" href="/" onClick=${route}>loom</a>
<${PinkTopNav}
slot="col2" className="grid-header-col-2" items=${[{ children: 'Docs', href: '/docs' }]}
onClick=${route}
/> </> <main>${children}</main>
<${PinkContainer} is=${el('footer')}>© 2026</>
</div> ` );Utility classes (u-flex, u-gap-16, u-padding-16, body-text-1) are part of the stylesheet and fill the gaps between components; the utilities layer sits last in the cascade so they win over component defaults.