# Get started

> Install Slab, import the elements you use, and make them yours. Everything you need, in order.

## Install it

Slab is one package, `slab-elements`, with Lit as a peer dependency.

```sh
pnpm add slab-elements lit
```

## Import what you use

Each element is its own module, and importing it registers its tag. Import the ones you use, and nothing else ships. An element made of parts, like Tabs, has a module for each part.

```js
import 'slab-elements/switch.js';

import 'slab-elements/tabs.js';
import 'slab-elements/tabs.tab.js';
import 'slab-elements/tabs.panel.js';
```

Any bundler resolves the imports, or an import map does without one.

## Use it like a native element

Attributes in, events out, the same as every built-in element. The events are the ones its native element fires, like "change", "input" and "toggle", and they bubble, so you can listen higher up too.

```html
<slab-switch label="Notifications" name="notifications"></slab-switch>

<script type="module">
  import 'slab-elements/switch.js';

  const toggle = document.querySelector('slab-switch');

  toggle.addEventListener('change', () => {
    console.log(toggle.checked);
  });
</script>
```

Every control needs a `label`, and one without throws rather than going unnamed. `hide-label` hides it from view and keeps it for screenreaders. Like a native control, the `checked` and `value` attributes are where it starts, and the properties are where it is now.

## In your framework

There's no wrapper package. The tag is the component, in React, Vue, Svelte, Rails, or plain HTML. React listens for events through a ref, Svelte needs nothing, and Vue needs to know which tags are custom elements. The [home page](index.md#usage) shows the same Disclosure in each.

```js
import vue from '@vitejs/plugin-vue';

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) => tag.startsWith('slab-'),
        },
      },
    }),
  ],
};
```

## Put it in a form

Slab's controls are form-associated, so they work in a plain `<form>` the way an `<input>` does. They submit their `name` and `value`, reset with the form, and come back when the browser restores the page. Validation is the native element's too: `required`, `pattern` and the rest mean what they mean on an `<input>`, and `checkValidity()`, `reportValidity()` and `setCustomValidity()` work the same.

```html
<form>
  <slab-text-field
    label="Email"
    name="email"
    type="email"
    required
  ></slab-text-field>

  <slab-checkbox
    label="Send me updates"
    name="updates"
    value="yes"
  ></slab-checkbox>

  <button>Sign up</button>
</form>
```

There's a [`<slab-form>`](components/form.md) too, if you'd like the form itself to be a Slab element.

## Style it

Nothing ships styled, so an element has no size and nothing to see until you give it one. Reach its pieces with `::part()` and its conditions with `:state()`. Every component's page lists both.

```css
slab-checkbox::part(checkbox) {
  block-size: 1rem;
  border: 1px solid currentcolor;
  inline-size: 1rem;
}

slab-checkbox:state(checked)::part(checkbox) {
  background-color: currentcolor;
}
```

## Make it your own

To go further, subclass it, set `styles`, and register it under a tag of your own. Slab's functional styles, like a label that's hidden but still read, survive yours.

```js
import Checkbox from 'slab-elements/checkbox.js';
import { css } from 'lit';

customElements.define(
  'acme-checkbox',
  class extends Checkbox {
    static styles = css`
      /* ... */
    `;
  },
);
```

Every [component's page](components.md) has a styled version to start from, with its source to copy and change.

## Your words, in any language

Slab brings no text of its own. Where an element has to make some, mostly names for screenreaders, it's English until you set an attribute, like Alert's `dismiss-label`. Text built from a value, like Pagination's "Page 3", is a function, so you can word and order it for your language.

```js
pagination.pageLabel = (page) => `Seite ${page}`;
```

## TypeScript

The types come with the package. Each element adds its tag to `HTMLElementTagNameMap`, so `document.querySelector('slab-switch')` is typed as Slab's `Switch`. There are no JSX types yet, so in React with TypeScript, declare the tags you use yourself.

## Browsers

Slab is tested in Chromium, Firefox and WebKit. Where a browser hasn't caught up on a feature, Slab uses it where it's there and leaves the platform's behavior where it isn't. Without CSS anchor positioning, for example, a popover is centered rather than placed beside its anchor. Every element still opens, closes, submits and is announced, everywhere.
