# AI Usage Guide

Use this guide when integrating the version of `@uh-design-system/component-library` installed in the current application. The guide is published with the package so its guidance stays aligned with that package version.

## Initialize in the application

The library ships standard web components. How to register them depends on how the application is built. In every setup, load the component and font styles once from the application entry point:

```ts
import '@uh-design-system/component-library/dist/component-library/component-library.css';
import '@uh-design-system/component-library/dist/fonts/fonts.css';
```

Those stylesheets declare the font faces and style the components, but they set no font on the application itself. Give the text of the application the body font, so that it matches the components:

```css
body {
  font-family: var(--ds-fontFamily-body);
}
```

The `ds-font-body` and `ds-font-heading` classes set the same fonts on a single element.

### Bundled application

In an application built with a bundler (Vite, webpack, Next.js and similar), import each component the application uses from `@uh-design-system/component-library/components/<tag>` and call its `defineCustomElement()` once from the entry point, before the first render. A component's `defineCustomElement()` also defines the components it renders internally, and calling it again is harmless:

```ts
import { defineCustomElement as defineDsIcon } from '@uh-design-system/component-library/components/ds-icon';
import { defineCustomElement as defineDsTextInput } from '@uh-design-system/component-library/components/ds-text-input';

defineDsIcon();
defineDsTextInput();
```

Write the specifier without a `.js` extension; the package export adds it. The bundler includes only the imported components, and no files have to be copied or served separately. `defineCustomElement()` uses the browser `customElements` registry, so with server rendering call it from code that runs only in the browser.

Icons are the exception to that: `ds-icon` resolves the component that draws the icon from its `dsName` property while it runs, so registering `ds-icon` does not register that component. Register `ds-icon-<name>` as well for every icon the application uses, writing `_` in the icon name as `-`:

```ts
import { defineCustomElement as defineDsIconArchive } from '@uh-design-system/component-library/components/ds-icon-archive';

defineDsIconArchive();
```

Components that draw an icon of their own need the same registration, for example `ds-icon-search` and `ds-icon-cancel-fill` for a `ds-text-input` of type `search`. An unregistered icon renders nothing and reports no error; the empty `<ds-icon-*>` element that is left in the DOM names the component that is missing.

### Plain HTML page

On a page without a bundler, load the published entry module. It registers every component, so no registration call is needed. Load it from a CDN pinned to the installed version, or from a copy of `dist/component-library/` that the page serves as it is:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@uh-design-system/component-library@<version>/dist/component-library/component-library.esm.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@uh-design-system/component-library@<version>/dist/component-library/component-library.css" />
```

### The loader export

The package also exports `defineCustomElements` from `@uh-design-system/component-library/loader`, which registers every component and loads each one when it is first used. Prefer the per-component imports above in bundled applications. The loader finds its component chunks through a computed dynamic import: webpack follows the chunk hints in it, but Vite and Rollup skip it, so every component registers and none of them renders, with no error, in the development server and in the production build alike.

## Use a component

Use the documented public component API. Component properties use the `ds` prefix. In HTML, write camelCase property names as kebab-case attributes, for example `dsName` as `ds-name`:

```html
<ds-icon ds-name="archive"></ds-icon>
```

Do not rely on undocumented DOM structure, internal CSS classes, or source modules. Check the API available in the installed package version before using a component or its properties. The package describes its own API in two files: `dist/docs.json` lists every component with its properties, events, methods and slots, and `dist/types/components.d.ts` declares the same API as TypeScript types.

## Use a component in React

React 19 supports web components natively, so no wrapper package is required. Register the components as described in "Bundled application" before the first render. Properties can then be written in camelCase or kebab-case:

```tsx
<ds-icon dsName="archive"></ds-icon>
```

React sets a camelCase name as a property only when the element is already defined; otherwise it writes it as an attribute, which the browser lowercases to `dsname`, and the component never receives it. If the components may be defined after React renders, for example when they come from a separately loaded script, write properties as kebab-case attributes (`ds-name`), which work either way.

Handle a component event with a property named `on` followed by the event name exactly as the component emits it. The name is case-sensitive, so the `dsChange` event is handled by `ondsChange` and not by `onDsChange`, and a handler whose name does not match is never called and reports no error:

```tsx
<ds-text-input ds-label="Email" ondsChange={handleChange}></ds-text-input>
```

React does not know the component tags. Declare the ones the application uses, and reference the package types to bring the `HTML*Element` interfaces into scope:

```ts
/// <reference types="@uh-design-system/component-library" />
import type { HTMLAttributes, Ref } from 'react';

type DsElement<T> = HTMLAttributes<T> & Record<string, unknown> & { ref?: Ref<T> };

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'ds-icon': DsElement<HTMLDsIconElement>;
      'ds-text-input': DsElement<HTMLDsTextInputElement>;
    }
  }
}
```

For typed components and typed event properties instead of these declarations, install `@uh-design-system/component-library-react` and import the components from it. It registers the components that it imports, so no `defineCustomElement()` calls are needed; load the styles as described above. Note that its event properties are named differently from the native ones: the `dsChange` event is `onDsChange` here.

```tsx
import { DsIcon, DsTextInput } from '@uh-design-system/component-library-react';

<DsIcon dsName="archive" />;
<DsTextInput dsLabel="Email" onDsChange={handleChange} />;
```

## Use the shared store

Use the public `<ds-store>` component to set the language for assistive and error messages. Supported languages are `en`, `fi`, and `sv`; the default is `en`.

```html
<ds-store ds-language="fi"></ds-store>
```

In a bundled application, register `ds-store` like any other component, from `@uh-design-system/component-library/components/ds-store`. The store also provides `setLanguage()` and `getLanguage()` methods. Wait until the custom element is defined before calling them, and do not import the internal store module:

```ts
await customElements.whenDefined('ds-store');
const store = document.querySelector('ds-store') as HTMLDsStoreElement;
await store.setLanguage('fi');
const language = await store.getLanguage();
```

`HTMLDsStoreElement` and the other element types are declared by the package types. In an application that imports nothing from the package in TypeScript, reference them explicitly with `/// <reference types="@uh-design-system/component-library" />`.
