
# Styles

The page works; now it should look like a packing list. The starter's `src/styles.css` sets the page-wide basics and the color variables, `--text`, `--muted`, `--line`, and `--accent`. Styles that belong to one component live with that component, written with the `css` tag.

## A styled row

Update `src/components/item.ts`:

```ts
// One row of the list, with styles that apply to this row and nothing else.
import { type ReadableSignal, type View, computed, css, html } from "zerolith";
import { type Item, remove, toggle } from "../store.ts";

const row = css`
    :scope {
        display: flex; align-items: center; gap: 0.75rem;
        padding: 0.5rem 0; border-bottom: 2px solid var(--line);
    }
    label { display: flex; align-items: center; gap: 0.75rem; flex: 1; }
    :scope[data-packed="true"] label {
        color: var(--muted); text-decoration: line-through;
    }
`;

export function ItemRow({ item }: { item: ReadableSignal<Item> }): View
{
    const name = computed(() => item.get().name);
    const packed = computed(() => item.get().packed);
    return html`
        <li class=${row} data-packed=${packed}>
            <label>
                <input type="checkbox" .checked=${packed}
                    @change=${() => toggle(item.get().id)}>
                ${name}
            </label>
            <button type="button" aria-label="Remove ${name}"
                @click=${() => remove(item.get().id)}>Remove</button>
        </li>`;
}
```

`css` returns a style sheet scoped to the elements that use it: `class=${row}` applies it to the row. Inside it, `:scope` is the row itself, and the other rules match only inside the row, so `label` here never styles a label anywhere else on the page. The styles are added to the document once, however many rows there are, with the browser's `@scope` rule and no shadow DOM, so the page's own styles and your design tokens still reach in.

`data-packed=${packed}` turns the item's state into an attribute the style sheet can select, which keeps the rule in CSS rather than in a class name built in JavaScript. The [styles guide](/guide/styles/) shows where a scope stops when one styled component sits inside another.

## A styled page

The page's styles can live in a stylesheet of their own, beside the component. Create `src/components/packing.css`:

```css
:scope
{
    display: grid;
    gap: 1.5rem;
}

h1,
p
{
    margin: 0;
}

ul
{
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 2px solid var(--line);
}
```

Then import it in `src/components/packing.ts`:

```ts
// The packing list page: progress, the filters, the rows, and a note when
// the filter leaves nothing to show. Its styles are in packing.css.
import { type View, computed, each, html, when } from "zerolith";
import { items, packedCount, shown } from "../store.ts";
import { AddItem } from "./add-item.ts";
import { Filters } from "./filters.ts";
import { ItemRow } from "./item.ts";
import page from "./packing.css?scoped";

export function Packing(): View
{
    const total = computed(() => items.get().length);
    const empty = computed(() => shown.get().length === 0);
    return html`
        <section class=${page}>
            <h1>Packing list</h1>
            <p>${packedCount} of ${total} packed</p>
            ${Filters()}
            <ul>${each(shown, (item) => item.id, (item) => ItemRow({ item }))}
            </ul>
            ${when(empty, () => html`<p>Nothing to show here.</p>`)}
            ${AddItem()}
        </section>`;
}
```

`?scoped` on the import turns the file into the same scoped style sheet a `css` literal makes, and `class=${page}` applies it the same way: `:scope` is the `section`, and the rules stop at the rows, which have styles of their own. A literal suits a few rules beside the markup, as in the row; a file suits a longer stylesheet, which your editor checks and completes as CSS. `zerolith dev` applies an edit to the file in place, without reloading the page.

The page is now a `section` with its own scoped styles, and the list is the finished one. `src/components/add-item.ts` and `src/components/filters.ts` stay as they were.

## What you learned

- `css` writes a style sheet scoped to one component, applied with `class=${styles}`.
- `:scope` is the element the styles apply to; other rules match only inside it.
- A stylesheet imported with `?scoped`, as `import page from "./packing.css?scoped"`, is scoped the same way, for styles that read better in a file of their own.
- Attributes bound to state, such as `data-packed`, let CSS follow the state.

