# Tag

> A tag for topics and filters. A CSS component with one class and no JavaScript.

A tag labels content: topics on an article, chosen filters above a list. If the tag says what state something is in, such as “Approved” or “Overdue”, [Badge](/components/badge.md) is the right choice instead.

## How to use it

**Plain HTML**

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/tag/tag.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<span class="lt-tag">Housing benefit</span>
<span class="lt-tag" data-variant="filled">Nursery</span>
<span class="lt-tag" aria-disabled="true">Archived</span>
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/tag.css"
```

`lt` is used in two ways, and which one depends on whether you create the element or find it.

**If you create the markup,** spread the attributes in. That is the way in React, Astro and anything else that renders:

```tsx
import { lt } from "@lo-tek/interfaces/react"


<span {...lt.tag()}>Housing benefit</span>
```

The import is from `/react` here, since the block is JSX. From there the keys are `className` and `htmlFor`. In Astro and anything else without React, import `@lo-tek/interfaces` and you get `class` and `for`.

**If you have the element in a variable,** set them on it with `setAttributes`. That is the way without JSX, whether you just created the element or found it in a page the server sent:

```ts
import { lt } from "@lo-tek/interfaces"


const tag = document.createElement("button")
tag.type = "button"


lt.setAttributes(tag, lt.tag({ selectable: true }))
tag.setAttribute("aria-pressed", "false")
```

| `data-variant` | Used for |
| - | - |
| *(omitted)* | Outline. The default. |
| `filled` | Muted surface, when the tags sit on a light surface |

## Filters that can be toggled

Three filters above a list of cases. “Approved” is selected, the other two are not, and `aria-pressed` says which is which:

**Plain HTML**

```html
<h3 class="lt-heading" data-size="xs" id="filters">Show cases with status</h3>


<div role="group" aria-labelledby="filters">
<button class="lt-tag" data-selectable aria-pressed="true" type="button">Approved</button>
<button class="lt-tag" data-selectable aria-pressed="false" type="button">In progress</button>
<button class="lt-tag" data-selectable aria-pressed="false" type="button">Rejected</button>
</div>
```

`<div role="group">` with a label is what ties the three together. Without it they are three loose buttons, and someone listening to the page does not know they belong to the same question.

`data-selectable` gives hover and a focus indicator. The element has to be a `<button>`, and you set `aria-pressed` yourself:

```html
<script type="module">
  for (const tag of document.querySelectorAll(".lt-tag[data-selectable]")) {
    tag.addEventListener("click", () => {
      const selected = tag.getAttribute("aria-pressed") === "true"
      tag.setAttribute("aria-pressed", String(!selected))
    })
  }
</script>
```

`aria-pressed` is what makes the screen reader say “pressed” or “not pressed”. Colour alone says nothing.

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-tag` | The tag. The variant comes from `data-variant`. |

| Variable | Default |
| - | - |
| `--lt-tag-padding` | `var(--lt-spacing-0-5) var(--lt-spacing-2)` |
| `--lt-tag-radius` | `var(--lt-spacing-1)` |

See [Customising](/customising.md) for how the variables and the layer work.

## Accessibility

- A tag that cannot be pressed should not look as if it can. Use `data-selectable` only on real buttons.
- If you have many filters, put them in a list with a heading that says what they filter.
- If the tag should be removable, make a separate button inside it with text that says what is removed: “Remove the Approved filter”, not just a cross.
