Theme Library Assets

Package reusable Kida components with CSS and JavaScript for Bengal themes

3 min read 649 words

Theme libraries let a Python package provide Kida templates, CSS, JavaScript, and runtime metadata to any Bengal theme. A theme opts in withlibrariesin theme.toml; the package exposes a small Python contract; Bengal handles fingerprinting, dev URLs, static output, and missing asset diagnostics.

Use this for component libraries such aschirp_ui, not for one-off site styles. Site and theme-owned files should still useasset_url().

Theme Setup

Declare the package in the theme manifest:

name = "vendor-theme"
libraries = ["vendor_ui"]

Then render provider-owned tags from the base template:

{{ library_asset_tags() }}
<link rel="stylesheet" href="{{ asset_url('css/style.css') }}">

library_asset_tags()renders only assets declared by the package contract. Your theme can still include its own bridge stylesheet or script with asset_url().

Package Contract

In the library package, exposeget_library_contract():

from pathlib import Path

from kida import PackageLoader


def static_path() -> Path:
    return Path(__file__).parent / "static"


def get_loader():
    return PackageLoader("vendor_ui", "templates")


def get_library_contract():
    return {
        "asset_root": static_path(),
        "assets": [
            {"path": "vendor.css", "mode": "bundle", "type": "css"},
            {
                "path": "transitions.css",
                "mode": "bundle",
                "type": "css",
                "output": "vendor.css",
            },
            {
                "path": "vendor.js",
                "mode": "link",
                "type": "javascript",
                "defer": True,
                "module": True,
            },
            {"path": "tokens.css", "mode": "none", "type": "css"},
        ],
        "runtime": ["vendor-ui"],
    }

The contract is intentionally plain Python. Paths are relative to asset_root unless you return an absolute source path. Output paths must be relative and cannot contain..; Bengal namespaces them under the package name, such as /assets/vendor_ui/vendor.css.

Asset Modes

Mode Build behavior Tag behavior Use when
link Emits the file through the normal asset pipeline. Renders one tag for the emitted asset. The file should stay separate.
bundle Concatenates assets with the sameoutput, then fingerprints the bundle. Renders one tag for the bundle. A package splits CSS/JS internally but themes should load one file.
none Does not emit the file. Renders no tag. The asset is metadata-only or consumed by another package process.

CSS and JavaScript emitted throughlink or bundleuse the normal Bengal asset manifest. In development, URLs stay stable. In static builds, URLs are fingerprinted.

Manifest Provenance

Provider-managed assets add optional provenance toasset-manifest.json:

{
  "assets": {
    "vendor_ui/vendor.css": {
      "output_path": "assets/vendor_ui/vendor.350f9b04.css",
      "fingerprint": "350f9b04",
      "size_bytes": 12345,
      "provenance": {
        "kind": "theme_library",
        "package": "vendor_ui",
        "mode": "bundle",
        "sources": ["vendor.css", "transitions.css"]
      }
    }
  }
}

sourcescontains contract-relative paths only. Bengal does not write absolute local filesystem paths into the manifest.

Tag Attributes

Useattributesor the common shorthands to control the generated HTML tag:

{
    "path": "vendor.js",
    "type": "javascript",
    "mode": "link",
    "defer": True,
    "attributes": {"crossorigin": "anonymous"},
}

Boolean attributes render without a value. String attributes are escaped. Bengal ownshref and src; declaring either as an attribute is rejected so fingerprinted URLs cannot drift.

Runtime Metadata

runtimeis a string or list of strings:

{"runtime": ["vendor-ui", "alpine"]}

Templates can read the deduplicated runtime list with:

{% if "vendor-ui" in library_runtime() %}
  ...
{% end %}

Use this for conditional template behavior. Do not use it to bypass asset declarations.

Diagnostics

Bengal validates the contract while resolving the theme library:

  • assetsentries need a non-empty path.
  • mode must be bundle, link, or none.
  • Runtime entries must be strings.
  • Output paths must be relative and stay inside the library namespace.
  • Tag attributes must be strings or booleans and cannot sethref or src.

During build, Bengal also checks rendered HTML for local CSS/JS references that were not emitted. In normal builds this is a warning with the first missing URL. In strict builds it is aBengalAssetError.

bengal build --strict

Run strict builds in CI for vendor themes. A browser console 404 should not be the first signal that a theme library asset is missing.