# selfstore-join Source: https://selfstore.dev/docs/widget-join Reference for the join widget - preview an invitation, join on an explicit yes, and get named outcomes for a spent invite or a device already following another share. Opening an invitation link. It previews first, joins on an explicit yes, and gives **named outcomes** instead of generic errors - "this device already follows another share" is a different sentence from "this invitation is spent", and the user can act on each. ```html ```
The join widget, light theme The join widget, dark theme
An invitation, previewed before anything is joined. Unstyled apart from the accent: this is the widget with one CSS custom property set.
## Properties | Property | Type | Default | Notes | | --- | --- | --- | --- | | `engine` | `JoinEngine \| null` | `null` | Your transport. Assign last. | | `link` | `string \| null` | `null` | The invitation. Also an attribute. | | `options` | `{ deadlineMs?: number }` | `{}` | Raise it when the engine's join opens a popup | | `variant` | `'card' \| 'banner'` | `'card'` | Also an attribute | | `flow` | `JoinFlow \| null` (read-only) | `null` | The underlying flow | ### `options.deadlineMs` Set it when joining opens an account chooser. The default network guard is generous for a request and short for a human reading a popup - a deadline that fires while someone is picking an account looks like a failure that is not one. ### `variant` `card` renders the full invitation: who shared, what level, the accept button. `banner` collapses it to one line - label, join, account switch - for a page that renders its own preview around the widget. ## Attributes | Attribute | Values | | --- | --- | | `link` | the invitation URL | | `variant` | `card` (default), `banner` | ```html ``` ## Events | Event | Detail | When | | --- | --- | --- | | `selfstore-joined` | `{ outcome: 'joined' }` | The device joined the share | | `selfstore-join-refused` | `{ outcome }` | A named refusal; `outcome` is the step reached | | `selfstore-cancelled` | none | The user backed out | `selfstore-join-refused` is not an error event. It fires for the two outcomes the journey expects and names - a spent invitation, or a device already following another share - so your app can offer the right next step rather than a retry button that will fail again. ## Parts Shared: `title`, `sub`, `hint`, `row`, `button`, `button-primary`, `link`, `status`, `status-ok`, `status-error`, `spinner`. Its own: `banner` - the row in the `banner` variant (also carries `row`). ## Labels Every string is a key with a default, and the widget ships English and French. The 14 keys it owns are listed on [every label key](https://selfstore.dev/docs/widget-labels#selfstore-join); how the resolution works is on [wording](https://selfstore.dev/docs/widgets-localization). Map of this site for a model: https://selfstore.dev/llms.txt Every page in one file: https://selfstore.dev/llms-full.txt