## Getting Started
Three steps: install the packages, load the scripts, link a theme. Then write markup: the elements bind themselves.
```html
<link rel="stylesheet" href="/dist/css/theme.min.css" />
<script src="pacem-foundation.min.js"></script>
<script src="pacem-core.min.js"></script>
<pacem-data id="counter" model="0"></pacem-data>
<pacem-button on-click="#counter.model++">+1</pacem-button>
```
### 1. Install
Pacem JS ships as scoped **npm** packages. Take the all-in-one bundle:
```
> npm install @pacem/pacem
```
...or only the packages you need (every one of them pulls in `@pacem/pacem-foundation` and `@pacem/pacem-core`):
```
> npm install @pacem/pacem-ui @pacem/pacem-scaffolding
```
> Same files on disk either way: the bundle just re-exports every package under one dependency.
### 2. Load the scripts
**No bundler.** Each package ships a minified script that extends one shared `window.Pacem` global.
Load `pacem-foundation` first, then `pacem-core`, then the packages you need: **order matters**.
```html
<!-- from the bundle: node_modules/@pacem/pacem/dist/browser/
(from single packages: node_modules/@pacem/pacem-{name}/dist/browser/) -->
<script src="/node_modules/@pacem/pacem/dist/browser/pacem-foundation.min.js"></script>
<script src="/node_modules/@pacem/pacem/dist/browser/pacem-core.min.js"></script>
<script src="/node_modules/@pacem/pacem/dist/browser/pacem-ui.min.js"></script>
<script src="/node_modules/@pacem/pacem/dist/browser/pacem-scaffolding.min.js"></script>
```
**With a bundler** (rollup, vite, esbuild, webpack…), import ES modules: from the bundle, or from single packages to ship only what you use.
```js
import { Components } from '@pacem/pacem-ui';
const { PacemButtonElement } = Components;
```
> Importing registers the custom elements, exactly as the scripts do: no `customElements.define` on your end.
### 3. Link a theme
The theme is native CSS (cascade layers, custom properties). One stylesheet carries every theme of yours;
`@pacem/pacem-theme-css` builds it from a small palette, adapting each color to WCAG contrast targets:
```
> npm install -D @pacem/pacem-theme-css
> npx pacem-theme-css init # pacem-themes.json, palette.json, theme.css
> npx pacem-theme-css build # dist/css/theme.min.css (+ -shell / -content splits)
```
Switch theme at runtime with an attribute, no reload: `<html light>`, or `data-theme="light"` on any subtree.
Any token can be overridden from your css too (`:root { --pacem-color-primary: #ff0085 }`): derived colors follow.
See the [Theme](/theme/colors) section for the result.
## Your first page
A to-do list: a `<pacem-data>` holds the items, a `<pacem-repeater>` renders them, a form adds new ones. No script of yours, just markup.
## Your own elements
Pacem JS comes with plenty of elements, but writing yours takes a class and two decorators:
`@CustomElement` registers the tag (and its template), `@Watch` turns a property into an observed attribute,
converted from its string form and bindable.
```ts
import { CustomElement, Watch, PropertyConverters, Components } from '@pacem/pacem-core';
/** Greets someone, by name. */
@CustomElement({
tagName: 'my-greeting',
template: `<span>Hello, <pacem-text text="{{ :host.name }}"></pacem-text>!</span>`
})
export class MyGreetingElement extends Components.PacemElement {
/** Gets or sets who to greet. */
@Watch({ converter: PropertyConverters.String }) name: string;
propertyChangedCallback(name: string, old: any, val: any, first?: boolean) {
super.propertyChangedCallback(name, old, val, first);
// react to changes here: the template is in place unless `first`
}
}
```
```html
<my-greeting name="{{ #profile.model.name }}"></my-greeting>
```
Pick the base class by what the element is:
- **`PacemEventTarget`**: non-visual elements (data, proxies, fetchers). It runs the `on-{event}` handlers and manages `disabled`.
- **`Components.PacemElement`**: visual ones. It adds `css`, `css-class`, `tooltip`, `behaviors` and the like.
> Decorators are TypeScript's (`"experimentalDecorators": true`), and class fields must stay accessors:
> set `"useDefineForClassFields": false`, or the fields shadow the watched properties.
## Lifecycle
`connectedCallback()` runs and `isConnected` turns `true`. **Bindings aren't processed yet**: Pacem first checks whether the rest of the DOM is in place.
The first `propertyChangedCallback()` of a property comes from its attribute, or from a non-null default value. Its 4th argument, `first`, is `true`. **Don't touch the template yet**: it may not be there.
Pacem's own `viewActivatedCallback()` runs and `isReady` turns `true`: the template is applied (descendants' included) and **bindings are live**. The right place for logic that needs the whole DOM. > The element fires `load`.
Any later change, as many times as it happens: `first` is `false` and the template is safe to use.
Removed from the DOM: `disconnectedCallback()` runs, `isConnected` and `isReady` turn `false`. > The place to remove listeners and dispose of resources. The element fires `unload`.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.