# Onboarding `{% onboarding %}` is a guided **product tour** — it dims the page, spotlights one element at a time behind a cutout, and walks the reader through your UI with a popover (a title and some content) per step. The body of the tag is the content the tour runs over; each target carries a `data-onboarding-tour-id` matching a step's `id`. A **Community Component** — wraps [Onboarding](https://gfazioli.github.io/mantine-onboarding-tour/) by **gfazioli**, **MIT** licensed, npm `@gfazioli/mantine-onboarding-tour`. A tour needs a "start" trigger and controlled state, which a static page can't wire up on its own, so the tag renders a **Start tour** button (relabel it with `triggerLabel`) that begins the tour and resets when it ends. The overlay, focus management, and element measurement are browser-only, so under server-side rendering or with JavaScript off the body content stays fully usable and the trigger is simply inert — nothing is hidden behind a tour that can't run. Use it as `{% onboarding %} … {% endOnboarding %}` in Markdown, or — for a tour built from Python data — call `component('aardvark', 'onboarding', tour=[…], children=…)`. ## Demonstrations ### A two-step tour Define the steps with `tour`, a JSON array of `{id, title, content}` objects. Mark each target in the body with a matching `data-onboarding-tour-id` using `attr={…}`. Click **Start tour** to run it. Save Share
Source: Markdown ```aardvark {% onboarding tour='[{"id": "save", "title": "Save your work", "content": "This button saves the current document."}, {"id": "share", "title": "Share it", "content": "Invite teammates to collaborate."}]' %} {% group %} {% button attr={'data-onboarding-tour-id': 'save'} %}Save{% endButton %} {% button variant='light' attr={'data-onboarding-tour-id': 'share'} %}Share{% endButton %} {% endGroup %} {% endOnboarding %} ``` Source: Python ```python component('aardvark', 'onboarding', tour=[ {'id': 'save', 'title': 'Save your work', 'content': 'This button saves the current document.'}, {'id': 'share', 'title': 'Share it', 'content': 'Invite teammates to collaborate.'}, ], children='…the UI the tour runs over…') ``` ### Custom trigger label and hiding the stepper `triggerLabel` sets the button text. The popover shows a step indicator by default; pass `withStepper=false` to hide it. Edit profile
Source: Markdown ```aardvark {% onboarding triggerLabel='Take the tour' withStepper=false tour='[{"id": "edit", "title": "Edit inline", "content": "Click any field to edit it in place."}]' %} {% button attr={'data-onboarding-tour-id': 'edit'} %}Edit profile{% endButton %} {% endOnboarding %} ``` ## With other components The tour runs over whatever you put in its body, so it composes with any built-in. Here it spotlights cards in a [CardGrid](/components/data-display/card/). Usage and trends. The latest events.
Source: Markdown ```aardvark {% onboarding triggerLabel='Tour the dashboard' tour='[{"id": "metrics", "title": "Your metrics", "content": "Live numbers update here."}, {"id": "activity", "title": "Recent activity", "content": "See what changed lately."}]' %} {% cardGrid cols=2 %} {% card title='Metrics' withBorder=true attr={'data-onboarding-tour-id': 'metrics'} %}Usage and trends.{% endCard %} {% card title='Activity' withBorder=true attr={'data-onboarding-tour-id': 'activity'} %}The latest events.{% endCard %} {% endCardGrid %} {% endOnboarding %} ``` ## Attributes Omit any attribute to take its default. The popover controls are all on by default; turn one off with `=false` (e.g. `withStepper=false`). | Attribute | Valid values | Description | | --- | --- | --- | | `tour` | A JSON array of `{id, title, content}` objects | The tour steps; each `id` matches a target's `data-onboarding-tour-id`. A malformed value warns at build time and the tour renders with no steps. | | `triggerLabel` | A string (default `Start tour`) | The opener button's text. | | `withSkipButton` | `true` / `false` (default `true`) | Show a "skip" control in the popover. | | `withPrevButton` | `true` / `false` (default `true`) | Show the "previous step" control. | | `withNextButton` | `true` / `false` (default `true`) | Show the "next step" control. | | `withStepper` | `true` / `false` (default `true`) | Show a step indicator in the popover. Set `=false` to hide it. | | `attr={…}` | An object of HTML attributes | Forwards raw HTML attributes onto the rendered wrapper (see below). | For tours built from data — or to pass the full upstream API (lifecycle callbacks, per-step `cutoutPadding` / `cutoutRadius`, …) — call `component('aardvark', 'onboarding', tour=[…], …)` from Python; every extra keyword is forwarded straight to the underlying component. ## CSS Selector The island wrapper carries a stable hook you can target from your own CSS: ```css [data-aardvark-onboarding] { /* your overrides */ } ``` The overlay, the focus cutout, and the popover are portaled to `document.body` and styled by the upstream `@gfazioli/mantine-onboarding-tour` stylesheet (bundled automatically via a CSS `@import`), so its own Mantine-style class names apply too. ## Injecting Attributes `attr={…}` forwards raw HTML attributes straight onto the rendered wrapper — anything Mantine doesn't model as a prop (ARIA, `data-*`, analytics hooks). It rides a separate channel from the component props, so it never collides with them. The same `attr={…}` channel is how you mark a **tour target**: put `data-onboarding-tour-id` on any element inside the body so a step's `id` can find it. Get started
Source: Markdown ```aardvark {% onboarding tour='[{"id": "cta", "title": "Get started", "content": "Click here to begin."}]' attr={'data-section': 'hero-tour'} %} {% button attr={'data-onboarding-tour-id': 'cta'} %}Get started{% endButton %} {% endOnboarding %} ``` Source: Python ```python component('aardvark', 'onboarding', tour='[{"id": "cta", "title": "Get started", "content": "Click here to begin."}]', attr={'data-section': 'hero-tour'}, children=component('aardvark', 'button', children='Get started', attr={'data-onboarding-tour-id': 'cta'})) ```