# Getting started

> Install LO-TEK, import what you need, and get the first component on screen.

## Install

```bash
npm install @lo-tek/interfaces
```

The package has no dependencies. The web components are ordinary `HTMLElement` classes, and nothing is registered by import alone, so a page that only uses the CSS components takes no JavaScript from the package. The Tailwind theme is plain CSS, so the package requires nothing from Tailwind.

## Import the stylesheets

`tokens.css` defines all the CSS variables, and every other stylesheet builds on it. It must be loaded, and comes first in the examples out of habit: the order between it and the others does not matter.

**With build tools**

One stylesheet per component, with `tokens.css` first:

```js
// main.js or main.ts, at the top
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/button.css"
```

Or everything in one import, without choosing:

```js
import "@lo-tek/interfaces/lotek.css"
```

`lotek.css` contains `tokens.css` and all the component stylesheets, so it replaces the whole list. The Tailwind theme is not included, and does not belong in a JavaScript import at all: `tailwind.css` is a `@theme` block Tailwind’s own compiler must read, and is set up as an `@import` in your own CSS. See [Tailwind](/tailwind.md).

**Without build tools**

One file with everything, one round trip:

```html
<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css" />
</head>
```

Or just what you use:

```html
<head>
  <link rel="stylesheet" href="/node_modules/@lo-tek/interfaces/src/tokens/tokens.css" />
  <link rel="stylesheet" href="/node_modules/@lo-tek/interfaces/src/components/css/button/button.css" />
</head>
```

Without a build step, some of the stylesheets fetch their parts with `@import`, which the browser only sees once the file has loaded. `dist/lotek.css` has everything flattened, without `@import`, and is therefore the fastest choice when you link. From a CDN, write the real path in the package, that is `@lo-tek/interfaces@0.36.0/src/tokens/tokens.css`. Short names like `@lo-tek/interfaces/tokens.css` are entries in `exports`, and only a build step reads those.

**If you link without a build step, use `lotek.css`.** One round trip of 103 kB, 13 kB compressed with gzip, and no `@import` the browser has to load the file to discover. The list with one stylesheet per component is for those with a build step: there, a page with only buttons does not load CSS for a dialog. The “Plain HTML” tab on each component page lists the links to the individual stylesheets, since the list also says what the component requires, and `lotek.css` covers each of them.

## Add the first component

With `tokens.css` and `button.css` imported:

**Code**

```html
<button class="lt-button">Submit application</button>
<button class="lt-button" data-variant="secondary">Save draft</button>
```

No registration, no start-up code. The CSS components are just classes.

## Register the web components

Frame and standalone components are web components, and must be registered once when the app starts. `defineLt()` registers all nine:

```ts
// main.ts, runs once, on import and not in an effect
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/field.css"
import { defineLt } from "@lo-tek/interfaces/register"


defineLt()
```

Without build tools, point at the built file:

```html
<script type="module">
  import { defineLt } from "https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/register.js"
  defineLt()
</script>
```

The call should happen as early as possible, before anything renders and never in a `useEffect`. An element that is in the page before registration is a plain `HTMLElement` with no behaviour, and a method call on it in that gap fails. The helpers `showToast`, `reportFailure`, `reportSuccess`, `extendSession` and `resetSession` instead wait for the registration and make the call when it arrives. The registration pulls in the code for all nine. If you use one of them, call its own function instead, like `defineLtField()` from `@lo-tek/interfaces/field`.

Calling them more than once is harmless, because the functions check themselves whether the element is registered. They also do nothing on a server, where there is no `customElements` to register in, so they can sit in a file that runs in both places.

```html
<lt-field>
  <label class="lt-label" for="name" data-required="symbol">Full name</label>
  <input class="lt-input" id="name" type="text" name="name" required />
  <p class="lt-help-text">As it appears in your passport.</p>
</lt-field>
```

If the label, the field and the help text are there, but the help text is not connected to the field with `aria-describedby`, the `define` function has not run. The markup in a `frame` component is yours and is shown regardless, with two exceptions: [Tabs](/components/tabs.md) shows only the first panel, and [Suggestion](/components/suggestion.md) hides the list, until they are registered, since they would otherwise jump when the script arrives. If the script fails, the user cannot reach the other tabs. Only the two standalone ones, `<lt-toast>` and `<lt-connection-status>`, are empty until they are registered. An `<lt-session-timeout>` shows nothing until the warning is due, and without registration it never comes.

## Use the entry points

**Stylesheets**

Each component has its own stylesheet, named after its page: `@lo-tek/interfaces/button.css`, `/checkbox.css`, `/table.css` and so on. Import the ones you use.

| Import | Contents |
| - | - |
| `@lo-tek/interfaces/lotek.css` | Everything in one file: tokens and every component, without `@import`. Not the Tailwind theme |
| `@lo-tek/interfaces/tokens.css` | All CSS variables. Required by everything else. |
| `@lo-tek/interfaces/<component>.css` | One component, with the same name as its page |
| `@lo-tek/interfaces/sr-only.css` | `.lt-sr-only`, text only screen readers get |
| `@lo-tek/interfaces/tailwind.css` | LO-TEK’s values as a Tailwind theme. Optional, see [Tailwind](/tailwind.md). |

Some stylesheets bundle what they need, so you do not have to import the parts separately: `field.css`, `error-summary.css`, `fieldset.css`, `search.css`, `session-timeout.css` and `suggestion.css`.

All the web components need a stylesheet. None of them uses shadow DOM, so the elements are ordinary elements with the system’s classes, and the classes must be loaded on the page.

**JavaScript and TypeScript**

The whole component API is in one namespace:

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


lt.button({ variant: "secondary" })
lt.input({ type: "email", state: "invalid" })
lt.badge({ color: "success" })
```

Type `lt.` in the editor to see what there is. If you use React, import from `@lo-tek/interfaces/react`. The calls are the same, but the return value uses `className` and `htmlFor`. See [Type-safe use](/type-safe-use.md).

| Import | Contents |
| - | - |
| `@lo-tek/interfaces` | `lt` with all the components, all the types, and the web component registrations |
| `@lo-tek/interfaces/react` | The same `lt`, but with `className` and `htmlFor` |
| `@lo-tek/interfaces/react-jsx` | Types for web components in JSX |
| `@lo-tek/interfaces/dom` | `setAttributes`: applies an attribute set to an element without JSX |
| `@lo-tek/interfaces/register` | `defineLt`: registers all the web components in one call |
| `@lo-tek/interfaces/diagnostics` | `diagnoseMarkup`: checks HTML against the elements and classes, as the editor does. See [The editor](/the-editor.md) |
| `@lo-tek/interfaces/field` | `defineLtField`, the class `LtField` |
| `@lo-tek/interfaces/session-timeout` | `defineLtSessionTimeout`, the class `LtSessionTimeout`, `extendSession` and `resetSession` |
| `@lo-tek/interfaces/connection-status` | `defineLtConnectionStatus`, the class `LtConnectionStatus`, `reportFailure` and `reportSuccess` |
| `@lo-tek/interfaces/tabs` | `defineLtTabs`, the class `LtTabs` |
| `@lo-tek/interfaces/error-summary` | `defineLtErrorSummary`, the class `LtErrorSummary` |
| `@lo-tek/interfaces/popover` | `defineLtPopover`, the class `LtPopover` |
| `@lo-tek/interfaces/toast` | `defineLtToast`, the class `LtToast`, `showToast` |
| `@lo-tek/interfaces/suggestion` | `defineLtSuggestion`, the class `LtSuggestion` |
| `@lo-tek/interfaces/dialog` | `defineLtDialog`, the class `LtDialog` |
| `@lo-tek/interfaces/field-core` | `computeFieldAttributes`: what `lt.field` and `<lt-field>` share |
| `@lo-tek/interfaces/host-element` | `HostElement` and `defineElement`: the base the web components inherit from |
| `@lo-tek/interfaces/tokens` | `cssTokens`, `colorTokens`, `darkColorTokens`, `darkTokens`, the types `CssToken`, `ColorToken`, `Breakpoint` and `Container`, `Breakpoints`, `Containers`, and what the colour families, roles and layers are for |

Each CSS component also exists as its own entry point (`@lo-tek/interfaces/button`, `/badge`, `/link` and so on) with a function named the same as the component. The exception is `/switch`, where the function is called `switchControl`, since `switch` is a reserved word. The builder functions for the web components, like `lt.tabs()` and `lt.dialog()`, have no entry point of their own: they are in `lt` and in the main entry point. `/tabs`, `/dialog` and the others have the class and the `define` function.

`lt` is optional. `class="lt-button" data-variant="secondary"` by hand gives the same result; the functions exist to catch typos.

## Understand versioning

The package follows [semantic versioning](https://semver.org/). The public API is larger than the functions: the class names, the attributes the builder functions write (`data-*` and `aria-*` included), the token names, the `--lt-*` variables and the entries in `exports` are all things you can build on.

Before 1.0, a new minor version, such as a move from 0.x to 0.(x+1), can have breaking changes. They are then listed under the heading “Breaking” in the changelog, with what you need to change. From 1.0, none of these change without a new major version.

`npm install` writes the version with `^` in front. Below 1.0, `^` only accepts new patches within the same minor version, so you get a new minor version only when you ask for it, by writing the new number in `package.json` or installing the package again.

The package is pure ESM, with no CommonJS build. Use `import`.

What has changed in each version is in [CHANGELOG.md](https://github.com/MarkusAugust/lo-tek/blob/master/designsystem/CHANGELOG.md), which also ships with the package.

## Go further

- [Frameworks](/frameworks.md): concrete setup for plain HTML, React, Astro and Datastar
- [The editor](/the-editor.md): completion and error messages in VS Code and JetBrains, also without TypeScript
- [Design tokens](/design-tokens.md): which variables exist, and what they are called
- [Tailwind](/tailwind.md): setup and LO-TEK’s values as utility classes
- [Button](/components/button.md): the simplest component to start with
- [Patterns](/patterns/form.md): whole forms, lists and pages put together
