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

```html
<div class="lt-card">
<h3 class="lt-card__title">Runner's policy AV-2079-0233</h3>
<p>Taken out 4 March. Premium EB 1,200 a month.</p>
<span class="lt-badge" data-color="success">Active</span>
</div>


<div class="lt-card" data-variant="filled">
<h3 class="lt-card__title">Claim AV-2079-0481</h3>
<p>Claim denied. Black ICE is an act of God.</p>
<button class="lt-button" data-variant="secondary">Appeal the decision</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}>Claim AV-2079-0477</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 = `/claims/${claim.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).

**kotlinx.html**

```kotlin
// Once for the whole app, in the page template: every stylesheet, from the WebJar.
head { link(rel = "stylesheet", href = LotekWebJar.CSS) }
```

On a Kotlin or Java server, the same with kotlinx.html and `lo-tek-kotlinx-html`. The builder functions are in `Lt`, with an enum for each list of values:

```kotlin
import kotlinx.html.*
import no.lotek.*
import no.lotek.html.lt


fun FlowContent.policies() {
    div {
        lt(Lt.card())
        h3 { lt(Lt.card.title); +"Runner's policy AV-2079-0233" }
        p { +"Taken out 4 March. Premium EB 1,200 a month." }
        span { lt(Lt.badge(color = BadgeColor.SUCCESS)); +"Active" }
    }
    div {
        lt(Lt.card(variant = SurfaceVariant.FILLED))
        h3 { lt(Lt.card.title); +"Claim AV-2079-0481" }
        p { +"Claim denied. Black ICE is an act of God." }
        button { lt(Lt.button(variant = ButtonVariant.SECONDARY)); +"Appeal the decision" }
    }
}
```

| `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 claim</h3>
<p>All attachments, messages and the small print 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.
