packages
Give a page a new shape
A package can restyle Leaf, add one element, or carry a related widget family. This tutorial builds the smallest useful package: a reusable callout made from one registry entry and one CSS rule.
Start with two files
Create a package in the project, then check the empty composition:
$ leaf package init packages/callout
$ leaf package check packages/callout
The widget in this tutorial needs only these files:
packages/callout/ registry.json theme.css
A project-wide package conventionally lives at .leaf/. A package
kept elsewhere joins a page with --package. In the commands
below, PAGE is the page directory to create or update:
$ leaf page init --package packages/callout PAGE
The complete package contract covers user packages, bundled packages, contribution directories, composition order, and replacement rules.
package init also creates empty contribution directories for
guidance, browser modules, widgets, and vendor files. The CSS-only widget here
leaves them untouched.
To start with behavior instead, name the first element while creating the package:
$ leaf package init packages/risk-notes --widget lf-risk-note
Leaf writes a valid prose-widget registry entry and its one-shot browser
module, then checks the complete candidate before changing the package. The
tutorial below stays with the smaller CSS-only form so each contract remains
visible. A behavior module imports Leaf's package API from
../runtime/widget-api.js; it registers each interactive
capability once with commands(). The same live command rows feed
keyboard dispatch, help, accessibility shortcuts, and—when
decision names the action—the controls shown inline for an Ask.
State the look
A package's theme.css joins Leaf's existing cascade. This package
only styles the element it introduces:
lf-callout {
display: block;
padding: var(--sp-3);
border: 1px solid var(--rule);
border-radius: var(--r);
background: var(--field);
--lf-frame: 1;
}
--lf-frame: 1 tells the shared layout that this rule draws the
widget's inset. The opening
theme token block
lists values such as --accent that a package may override for the
whole page. Presentation used by only one page stays in that version's own
<style>.
Declare the element
The page will author the callout as ordinary readable markup:
<lf-callout id="migration-warning">
<strong>Migration window</strong>
Writes pause for about two minutes.
</lf-callout>
Its complete registry.json entry validates the attributes and
tells Leaf that the body is prose. x-example is the specimen an
author queries with the entry:
{
"lf-callout": {
"description": "A short warning or constraint that belongs in the reading flow.",
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*$"
}
},
"required": ["id"],
"additionalProperties": false,
"x-content": "prose",
"x-upgrade": false,
"x-example": "<lf-callout id=\"migration-warning\"><strong>Migration window</strong> Writes pause for about two minutes.</lf-callout>"
}
}
x-content and x-upgrade are the two Leaf
declarations every widget requires. The ordinary JSON Schema fields validate
its attributes; description and x-example make the
merged registry useful to an author.
The registry-key reference lists every
x-* declaration. A CSS-only widget stops here.
Compose and check the page
$ leaf package check packages/callout
$ leaf page init --package packages/callout PAGE
$ jq '.["lf-callout"], .["$keys"]' PAGE/registry.json
$ leaf version check PAGE --render
Re-running page init is the explicit update for an existing page.
Pages that are not re-initialized keep their vendored layer unchanged.
- Registry keys
-
The generated reference for declarations such as
x-dataandx-request. - Package contract
- Composition, guidance, browser modules, external data, requests, and validation.
- Bundled default package
- A complete package containing the widgets used across Leaf pages.