# Widgets overview
Source: https://selfstore.dev/docs/widgets
One element mounts the whole storage journey; the rest of the section is for apps that place the pieces themselves. Framework-free custom elements you theme with CSS and reword for your locale.
The screens for choosing where data lives, showing whether it is saved, managing
backups, sharing and joining are the same in every app. `selfstore/widgets`
ships them as **custom elements**: plain HTML you drop into any page, theme with
CSS, and reword for your locale.
## Start here
Most apps need one element and two lines:
```html
```
```js
const store = await selfstore('app', { drive: { clientId } });
document.querySelector('selfstore-storage').store = store;
```
[``](https://selfstore.dev/docs/widget-storage) is the whole storage journey: it
asks the first-run question when there is no home yet, and shows the panel once
there is one. Which of the two, and when, follows the engine's own status.
**If that is what you needed, you are done** - the rest of this section is for
apps that place the pieces themselves.
They are skins over the same headless [flows](https://selfstore.dev/docs/advanced) the API exposes.
Every ordering and failure rule lives in the flow and its tests, so nothing here
is a black box, and dropping down to the flow later costs you no capability.
## Register them
```ts
import { selfstore } from 'selfstore';
import { defineSelfstoreWidgets } from 'selfstore/widgets';
defineSelfstoreWidgets(); // registers every element once
const store = await selfstore('my-app');
```
`defineSelfstoreWidgets()` is safe to call twice - it skips names already
defined. It touches `customElements`, so it is browser-only: call it from client
code, not during server rendering. Pass a prefix to register under your own tag
names:
```ts
defineSelfstoreWidgets('acme'); // , , ...
```
The gate builds its own connect child and reads the prefix back off its own tag
name, so a custom prefix keeps the pair together.
### Register one, not nine
Naming `defineSelfstoreWidgets` is what pins all nine elements into your
bundle - convenient, and the reason a small app ships widgets it never renders.
Where size matters, register only what you place:
```ts
import { defineStatus } from 'selfstore/widgets';
defineStatus(); // , and nothing else
```
| Function | Registers |
| --- | --- |
| `defineConnect` | `` |
| `defineStatus` | `` |
| `defineShare` | `` |
| `defineJoin` | `` |
| `defineBackups` | `` |
| `defineGate` | ``, with the connect child it builds |
| `defineDestination` | ``, with the connect and status it composes |
| `defineStorage` | ``, and therefore both of the above |
| `defineAccount` | ``, with the status row it composes |
Each takes the same optional prefix, and each pulls in what it composes - so
the three that build children are honest about their weight rather than
breaking at runtime.
## The pieces
**Storage**, if you place them yourself rather than letting
[``](https://selfstore.dev/docs/widget-storage) decide:
| Element | What it renders |
| --- | --- |
| [``](https://selfstore.dev/docs/widget-gate) | The first-run screen, before there is a durable home |
| [``](https://selfstore.dev/docs/widget-connect) | The journey itself: pick, authorize, resolve, set a password |
| [``](https://selfstore.dev/docs/widget-destination) | The panel once there is a home: where, when, and how to change it |
| [``](https://selfstore.dev/docs/widget-account) | The same answer at header size, two gestures instead of four |
| [``](https://selfstore.dev/docs/widget-status) | One line, or one dot: is the data saved, and where |
**Everything else**, which no composer covers because it depends on your app:
| Element | What it renders |
| --- | --- |
| [``](https://selfstore.dev/docs/widget-backups) | Several named backups on one home |
| [``](https://selfstore.dev/docs/widget-share) | Hand out a link so others can read or edit |
| [``](https://selfstore.dev/docs/widget-join) | Open a share link someone sent |
Import only the ones you mount. A store that must never be shared simply never
imports share and join, and that code stays out of the bundle - which is the
point of the [sensitive-app](https://selfstore.dev/docs/sensitive) posture.
## Wire one
Elements are **inert until wired**. They render nothing until you assign the
property that gives them something to drive - usually `store`:
```html
```
**Order matters.** Every setter that changes the journey rewires the flow, and
the store is what makes wiring possible at all. Assign the shape first
(`labels`, `icons`, `targets`, `options`), then `store`. The gate is stricter
still: it reads its frame when it opens, so `labels` set after it is on screen
reach the child but not the frame's own title.
These are **properties, not attributes** - they take objects and functions,
which an HTML attribute cannot carry. A handful of scalar knobs are also
attributes; each element's page lists which.
## The five customization layers
Nothing here requires forking a widget:
1. **[CSS custom properties](https://selfstore.dev/docs/widgets-styling)** - `--selfstore-accent`,
`--selfstore-radius` and thirteen more. They cross shadow boundaries, so one
declaration on a parent themes everything below.
2. **[`::part()`](https://selfstore.dev/docs/widgets-styling)** - every significant node carries a
part name, so you restyle any piece without touching internals.
3. **[Labels](https://selfstore.dev/docs/widgets-localization)** - every string is a key with a
default. Widgets ship English and French; override a key to reword, or a
whole map to translate.
4. **Attributes and properties** - the full journey is the default; each knob
removes or narrows a piece. `icons` is one of them, and `defaultIcons` is
what it starts from: a glyph per destination kind - a cloud for a hosted
drive, a document for a file on the device, a server for WebDAV, a bucket
for object storage. Import it to override one and keep the rest, rather than
redrawing a set:
```ts
import { defaultIcons } from 'selfstore/widgets';
el.icons = { ...defaultIcons, file: myOwnFileGlyph };
```
5. **[Events](https://selfstore.dev/docs/events)** - every widget emits bubbling, composed
`selfstore-*` events so the host reacts without polling.
## Fonts and colours are inherited, not imposed
The widgets set `font: inherit` and `color: inherit` on their host element, and
their neutral tones are derived from `currentColor` with `color-mix()`. Panels
use the `Canvas` and `CanvasText` system colours.
In practice: **a widget on a dark page is dark, with no configuration**, as long
as your page sets a colour. What it does not inherit is your accent - that one
is a deliberate `--selfstore-accent`, because a brand colour is a decision, not
a default.
## They respond to their own width
Each widget's stack is a CSS container (`container-type: inline-size`), and the
layout switches below **480px of the widget's own width** - not the viewport's.
A widget in a narrow sidebar stacks correctly on a wide screen, with no host CSS
and no media query of yours.
## TypeScript
The element classes are exported, so a `querySelector` can be typed and a
subclass can extend one:
| Export | For |
| --- | --- |
| `SelfstoreGateElement` | `` |
| `SelfstoreStorageElement` | `` |
| `SelfstoreDestinationElement` | `` |
| `SelfstoreAccountElement` | `` |
| `SelfstoreConnectElement` | `` |
| `SelfstoreStatusElement` | `` |
| `SelfstoreBackupsElement` | `` |
| `SelfstoreShareElement` | `` |
| `SelfstoreJoinElement` | `` |
| `FlowWidget` | The abstract base every widget extends |
| `WidgetLabels` | `Record` - the shape of a `labels` map |
```ts
import type { SelfstoreGateElement } from 'selfstore/widgets';
const gate = document.querySelector('selfstore-gate');
gate?.targets = { file: true };
```
Registering under a custom prefix and extending a class are the same mechanism:
`defineSelfstoreWidgets('acme')` registers the stock classes under your names,
while `customElements.define('acme-gate', class extends SelfstoreGateElement {})`
lets you override behaviour. The gate finds its connect child by rewriting its
own tag name, so a subclass pair keeps working as long as both share a prefix.
## When the API fits better
Widgets are the common journeys rendered fast. When you want the connect journey
inside your own components, drive [`selfstore/flows`](https://selfstore.dev/docs/advanced) directly -
the widgets are a thin skin over exactly that. Every element also exposes its
`flow` for programmatic control, so you can mount the widget and still drive it
from code.
Map of this site for a model: https://selfstore.dev/llms.txt
Every page in one file: https://selfstore.dev/llms-full.txt