Styling & assets

Azox has no CSS pipeline. Files in public/ are copied to the build root untouched, and a page links to them the way any HTML page would.

The public directory

project
my-app/
├── pages/
│   └── index.azox
└── public/
    ├── style.css        →  /style.css
    ├── logo.svg         →  /logo.svg
    └── fonts/
        └── mono.woff2   →  /fonts/mono.woff2

A file keeps the same path in source and in the built site, so a link written during development is the link that ships.

Linking a stylesheet

Use a page's <head> block. Its contents are copied into the document head verbatim.

pages/index.azox
<head>
  <title>My app</title>
  <meta name="description" content="Built with Azox" />
</head>

<main>
  <h1>Hello</h1>
</main>

Use absolute paths (/style.css) rather than relative ones. A page at /blog/post is served from its own directory, so a relative path would resolve differently there.

Page titles

A <title> in the head block wins. Without one, the title falls back to the name in your package.json.

Applying classes

Attributes keep their HTML names — class, not className. Braces make one reactive.

classes
<div class="card">static</div>

<div class={isActive() ? 'card is-active' : 'card'}>
  reactive
</div>

Inline styles

styles
<div style="padding: 1rem">static</div>

<div style={'width: ' + progress() + '%'}>reactive</div>

Scripts

A plain script for behaviour that is not part of any page's reactive state — analytics, or a global click handler — goes in public/ and is linked from the head.

head
<head>
</head>

The head block is per page. There is no shared document layout in this version, so a stylesheet link is repeated in each page that needs it. Components cannot contribute to the head.

Scoped styles

A component can carry a <style> block. Its rules apply to that component's own markup and nothing else, so two components can both style .card without colliding.

components/Card.azox
<style>
  .card { border: 1px solid #333; padding: 1rem }
  .card .title { font-weight: 700 }
</style>

<article class="card">
  <h2 class="title">{title}</h2>
  <slot />
</article>

There is no runtime and nothing extra to load. Each selector is rewritten during the build to require an attribute, and the component's own elements are given it:

what the build emits
.card[data-azox-a1b2c3] { border: 1px solid #333; padding: 1rem }
.card .title[data-azox-a1b2c3] { font-weight: 700 }

The attribute lands on the element a selector actually targets — .card .title scopes the title, not its ancestor. A component used twice contributes its CSS once.

Slot content keeps the caller's scope. Markup nested inside a component tag was written by whoever used the tag, so the component cannot restyle it.

Reaching outside the component

:global(...) is the escape hatch for the times a component has to style something beyond itself.

:global
<style>
  :global(body) { margin: 0 }
</style>

A page's own styles

A <style> block in a page is not scoped. A page has no caller to be scoped against, and body written there means the document body, as it says.

What is not included

Beyond scoping a component's <style> block, Azox does nothing to your CSS: no bundling, no minification, no hashed filenames, no preprocessor. Files are served as written. If you need a build step for your styles, run it yourself and output into public/.

Next