# Card

> A box that groups content that belongs together. A CSS component with two classes and no JavaScript.

A frame around content that belongs together, such as one case in a list of cases. The card is a container, not a component with behaviour: the content decides what the user can do.

## 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/card/card.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/badge/badge.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/button/button.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<div class="lt-card">
<h3 class="lt-card__title">Housing benefit application</h3>
<p>Sent 4 March. Case number 2026-0481.</p>
<span class="lt-badge" data-color="success">Approved</span>
</div>


<div class="lt-card" data-variant="filled">
<h3 class="lt-card__title">Nursery place application</h3>
<p>We need a birth certificate before we can process the application.</p>
<button class="lt-button" data-variant="secondary">Upload attachment</button>
</div>
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/card.css"
import "@lo-tek/interfaces/badge.css"
import "@lo-tek/interfaces/button.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"


<div {...lt.card({ variant: "outline" })}>
  <h3 className={lt.card.title}>Application 2024/1187</h3>
  <p>In progress.</p>
</div>
```

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 card = document.createElement("a")
card.href = `/case/${caseFile.id}`


lt.setAttributes(card, lt.card({ interactive: true }))
```

`lt.card.title` gives the class for the heading. See [Type-safe use](/type-safe-use.md).

| `data-variant` | Used for |
| - | - |
| *(omitted)* | Outline on the page surface. The default. |
| `filled` | Muted surface, when the card should stand out from white without a border |

## The whole card as a link

**Plain HTML**

```html
<a class="lt-card" data-interactive href="#">
<h3 class="lt-card__title">See the whole case</h3>
<p>All documents, messages and decisions in one place.</p>
</a>
```

`data-interactive` gives hover and a focus indicator, but makes nothing clickable on its own. The element has to be an `<a>` or a `<button>`. A `<div>` with a click listener can neither be reached with the keyboard nor be announced as something to press.

If the card has several actions, the whole card should not be a link. The buttons then end up inside a link, and the user cannot press them without navigating. Make one clear link in the heading instead.

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-card` | The card itself. The variant comes from `data-variant`. |
| `.lt-card__title` | The heading inside the card |

| Variable | Default |
| - | - |
| `--lt-card-padding` | `var(--lt-spacing-4)` |
| `--lt-card-radius` | `var(--lt-spacing-2)` |

An example. A card that carries a whole section can take more space than one in a list:

**Plain HTML**

```html
<div class="lt-card">
<h3 class="lt-heading" data-size="s">Default</h3>
<p class="lt-paragraph">The spacing that comes with the package.</p>
</div>


<div class="lt-card roomy-card">
<h3 class="lt-heading" data-size="s">Roomy</h3>
<p class="lt-paragraph">Same markup, one more class.</p>
</div>
```

```css
.roomy-card {
--lt-card-padding: var(--lt-spacing-6);
}
```

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

## Accessibility

- The heading in the card should be a real heading element, at the right level for the page. The class sets the size, weight and line height, not the level.
- If the cards are a list, mark them up as a list with `<ul>` and `<li>`. The screen reader then says how many there are and where in the list the user is.
- Do not hide important information behind hover. It does not exist on a touch screen.
- The order in the markup is the order the keyboard follows. Moving something visually with CSS does not move focus.
