Resources
Plume templates can declare the CSS, JavaScript and images they need right next to the markup that uses them. Plume collects those declarations while rendering, and the host application turns them into real files instead of forcing everything inline.
The important idea is locality: write the resource next to the markup that needs it, and let the host decide how to fingerprint, inject, optimise or copy it.
How collection works
When a template renders, Plume records resource declarations in the render result. It does not assume where those files should live in the final site.
A host can then:
- Combine or fingerprint CSS.
- Emit JavaScript as modules.
- Scope component styles.
- Resolve static assets.
- Generate responsive images.
- Inject links and scripts into the final document.
A host typically emits fingerprinted resources under a path such as /assets/plume/. When embedding Plume yourself, Embedding explains how to emit collected resources.
Styles
Use @style for CSS that belongs to the current template:
@style {
.post-list {
display: grid;
gap: 1rem;
}
}
<section class="post-list">
@for post in posts {
<article>{post.title}</article>
}
</section>Scoped styles
A component's CSS often should not leak into the rest of the page. Use scoped styles for that:
@component Button(label, variant = "plain") {
@style(scoped) {
.button {
border-radius: 0.4rem;
}
.button.primary {
background: black;
color: white;
}
}
<button class="button" class+="{variant}">{label}</button>
}Scoped styles are normal CSS. Plume rewrites the selectors and marks the rendered fragment with a generated scope attribute.
Style files
CSS files are supported too:
@style(file: "styles/site.css")
@style(file: "components/card.css", scoped: true)Use inline styles when the CSS only makes sense next to the template. Use CSS files when the stylesheet is shared, large or edited independently.
Scripts
@script uses Plume's client script language by default:
@script {
let menu = page.query("#menu")
on ".menu-toggle".click {
menu.toggleClass("is-open")
}
}See Client scripts for the language reference.
Script files
Use .plume files when a script should live outside the template:
@script(file: "scripts/menu.plume")Raw JavaScript
Raw JavaScript is available as an explicit escape hatch:
@script(language: "javascript") {
document.documentElement.dataset.enhanced = "true";
}JavaScript files are treated as raw JavaScript automatically:
@script(file: "scripts/site.js")Scoped scripts
Scoped scripts belong to a rendered fragment. Inside the script, root is the fragment's top-level element:
@component Disclosure(title) {
@script(scoped) {
let button = root.query("button")
on button.click {
root.toggleClass("is-open")
}
}
<section>
<button>{title}</button>
@slot
</section>
}Scoped Plume scripts run once for each rendered fragment. Raw JavaScript modules are copied as modules and do not get root.
Assets
Hosts can expose an asset() function to resolve theme or application files:
<img src="{asset('images/avatar.png')}" alt="Avatar">Plume checks static asset references where the host provides enough information. The host decides the final public URL.
Use asset() for files you want to reference from attributes, such as favicons, downloads, fonts and images that do not need generated markup.
Assets in compiled templates
asset() works in both the interpreter and the compiled path. In a compiled template it is resolved at build time to a baked URL string literal, so there is no runtime lookup in the Wasm build. Because of that, the argument must be a string literal.
In PlumeKit, asset() resolves the framework's own files to the content-hashed Plume bundle: asset("app.js") becomes /app.<hash>.js and asset("app.css") becomes /app.<hash>.css. Your own Public/ files pass through by path, so asset("logo.png") becomes /logo.png.
Images
Use @image when the host supports image generation:
@image(
"hero.jpg",
alt: "Coastal path",
widths: [480, 960, 1440],
sizes: "(min-width: 960px) 960px, 100vw"
)Plume records the image reference and requested attributes. The host can then resolve the file, inspect dimensions, generate responsive variants and emit the final <img> markup.
Common arguments: src, alt, class, width, height, loading, decoding, fetchpriority, widths and sizes.
Use @image when you want the host to produce the <img> element or add image metadata. Use asset() when you only need a URL.