From 60199b8ba393b4f4c15b86e1030e7d794f20c140 Mon Sep 17 00:00:00 2001 From: Adeola Adeyemo Date: Wed, 25 Feb 2026 12:12:24 +0000 Subject: [PATCH 1/4] feat: Create documentation for web components Signed-off-by: Adeola Adeyemo --- docs/journeys/custom-css.md | 2 +- docs/journeys/web-components.md | 306 ++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 docs/journeys/web-components.md diff --git a/docs/journeys/custom-css.md b/docs/journeys/custom-css.md index 7ad38e64..5ebd14eb 100644 --- a/docs/journeys/custom-css.md +++ b/docs/journeys/custom-css.md @@ -17,7 +17,7 @@ Custom CSS lets you: - **Create unique designs** — go beyond the Design Builder's built-in controls. :::info -Custom CSS applies only to journeys using the **Concorde** design (not the End Customer Portal or legacy design). It is available on the **Professional** pricing plan and above. +Custom CSS applies only to journeys (not the End Customer Portal or legacy design). It is available on the **Professional** pricing plan and above. ::: If you plan to use Custom CSS with dark mode, see the [dark mode section](#dark-mode) below. diff --git a/docs/journeys/web-components.md b/docs/journeys/web-components.md new file mode 100644 index 00000000..63b7d2cc --- /dev/null +++ b/docs/journeys/web-components.md @@ -0,0 +1,306 @@ +--- +sidebar_position: 4 +--- + +# Web Components + +Web Components allow you to embed epilot Journeys directly into your website as native custom HTML elements. Unlike iframes, Web Components run within the page itself using the [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM), which keeps styles and scripts encapsulated while offering faster performance, better accessibility, and tighter integration with your host application. + +:::tip Why Web Components over iframes? + +- **Performance** — no iframe overhead; the Journey renders directly in your page. +- **Integration** — communicate with the Journey through standard HTML attributes instead of cross-frame messaging. +- **Accessibility** — screen readers and keyboard navigation work seamlessly. +- **Style encapsulation** — Shadow DOM prevents style collisions in both directions, with optional inheritance. + +::: + +## Quick Start + +### 1. Add the embed script + +Place the following script tag in your page, preferably within the `` section: + +```html title="Embed script" + +``` + +Loading the script with `async` ensures it downloads without blocking your page and executes as soon as it's available. The script auto-registers the `` custom element on load. + +### 2. Add the Journey element + +Place the `` custom element wherever you want the Journey to appear: + +```html title="Basic usage" + +``` + +Replace `` with the ID of the Journey you want to embed. + +### 3. You're all set + +The Journey will render inline on your page. Read on for the full attribute reference and advanced configuration options. + +## Attribute Reference + +All attributes are set as standard HTML attributes on the `` element. Boolean attributes accept `"true"` or `"false"` as string values. + +| Attribute | Type | Default | Description | +| ------------------------ | ----------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `journey-id` | `string` | — | **Required.** The ID of the Journey to render. | +| `mode` | `"inline"` \| `"full-screen"` | `"full-screen"` | The display mode. `inline` renders the Journey within the page flow. `full-screen` renders it as an overlay. | +| `lang` | `"de"` \| `"en"` \| `"fr"` | `"de"` | Overrides the UI language. This affects UI labels and copy, but does not automatically translate static content configured in the Journey Builder. | +| `top-bar` | `"true"` \| `"false"` | `"false"` | Whether to show the top navigation bar. | +| `scroll-to-top` | `"true"` \| `"false"` | `"true"` | Whether to scroll the page to the top of the Journey when the user navigates to a new step. | +| `close-button` | `"true"` \| `"false"` | `"true"` | Whether to show the close button in the top bar. | +| `context-data` | JSON string | — | Additional contextual data passed to the Journey and included with the submission. Must be a JSON-encoded string of key-value pairs. See [Context Data](#context-data). | +| `data-injection-options` | JSON string | — | Pre-fill Journey fields and control the starting step. Must be a JSON-encoded string. See [Data Injection](#data-injection). | +| `journey-token` | `string` | — | A JWT token used for [post-qualification Journeys](./post-qualification). | +| `is-embedded` | `"true"` \| `"false"` | `"false"` | Indicates the Journey is embedded on a host app. | +| `debug` | `"true"` \| `"false"` | `"false"` | Enables debug mode for development and troubleshooting. | + +## Examples + +### Inline Mode + +Render the Journey directly within the page flow: + +```html title="Inline mode" + +``` + +### Full-Screen Mode + +In full-screen mode, the Journey does not open automatically. You need to post a message to the window to trigger it: + +```html title="Full-screen mode" + + + + + +``` + +To close the Journey programmatically, post an `EPILOT/EXIT_FULLSCREEN` message in the same way: + +```javascript title="Closing the Journey" +window.postMessage( + { + type: 'EPILOT/EXIT_FULLSCREEN', + journeyId: '', + }, + '*' +) +``` + +### Multiple Journeys + +You can embed multiple Journeys on the same page. Each one operates independently: + +```html title="Multiple journeys" + + + +``` + +:::info Live Examples + +Interactive examples are available at `{{embed URL}}/stories`, where you can browse different embedding scenarios and configurations. + +::: + +## Context Data + +Use the `context-data` attribute to pass additional key-value pairs to the Journey. This data is included with the submission and can be used for tracking, attribution, or pre-configuring behavior. + +The value must be a JSON-encoded string. Only **string** and **numeric** values are supported: + +```html title="Passing context data" + +``` + +Numeric values are coerced to strings internally. + +## Data Injection + +Data injection allows you to pre-fill Journey fields with data and optionally start from a specific step. This is useful when your website has already collected some information (e.g. a product selection or address) and you want to carry it into the Journey. + +The `data-injection-options` attribute accepts a **JSON string** with the following structure: + +```typescript title="DataInjectionOptions" +type DataInjectionOptions = { + /** The step index to start the Journey from (0-based) */ + initialStepIndex?: number + /** Pre-fill data for each step */ + initialState?: Record[] + /** Control which blocks/fields are disabled */ + blocksDisplaySettings?: BlockDisplaySetting[] +} + +type BlockDisplaySetting = { + type: 'DISABLED' + blockName: string + stepIndex: number + blockFields?: string[] +} +``` + +### Setting data injection options + +Pass the JSON directly as a string attribute using single quotes around the attribute value: + +```html title="Pre-filling journey data" + +``` + +You can also set it dynamically via JavaScript: + +```javascript title="Setting data injection dynamically" +const el = document.querySelector('epilot-journey') + +el.setAttribute( + 'data-injection-options', + JSON.stringify({ + initialStepIndex: 1, + initialState: [ + { + 'Product Selection': { + selectedProduct: 'solar-panel-basic', + _isValid: true, + }, + }, + {}, + {}, + ], + blocksDisplaySettings: [ + { + type: 'DISABLED', + blockName: 'Product Selection', + stepIndex: 0, + blockFields: ['selectedProduct'], + }, + ], + }) +) +``` + +### Populating `initialState` + +`initialState` is an array where each element corresponds to a Journey step (by index). Each step entry is an object keyed by block name, containing the field values for that block. + +- Steps that should not be pre-filled must be empty objects `{}`. +- The array must be ordered sequentially to match step order. + +To discover the correct block names and field structure, open your Journey in **debug mode** from the Journey Builder and inspect the state for each step. + +## Dynamic Attribute Updates + +The `` element reacts to attribute changes. You can update attributes dynamically via JavaScript, and the Journey will re-render with the new configuration: + +```javascript +const journey = document.querySelector('epilot-journey') + +// Change language +journey.setAttribute('lang', 'en') + +// Update context data +journey.setAttribute('context-data', JSON.stringify({ source: 'checkout' })) +``` + +You can also call the `refresh()` method on the element to force a re-render: + +```javascript +document.querySelector('epilot-journey').refresh() +``` + +## Content-Security-Policy (CSP) + +If your website uses a Content-Security-Policy, you will need to allow epilot domains. Since Web Components don't use iframes, you only need the `script-src` rule — the `frame-src` rule from the [Content-Security-Policy](./content-security-policy) page is not required: + +```text title="Minimum CSP for Web Components" +script-src 'self' https://*.epilot.io https://*.epilot.cloud; +``` + +See the dedicated [Content-Security-Policy](./content-security-policy) page for additional guidance on nonces and inline script handling. + +## Migrating from iframes + +If you are currently embedding Journeys using iframes with the `__epilot` embed script, migrating to Web Components involves: + +1. **Replace the embed script** — swap the iframe bundle script for the Web Component embed script: + + ```diff + - + + + ``` + +2. **Replace the initialization code** — instead of calling `__epilot.init()`, use the `` custom element directly: + + ```diff + -
+ - + + + ``` + +3. **Update CSP rules** — the same epilot domain rules apply. See [Content-Security-Policy](./content-security-policy). + +The attribute names on the Web Component map directly to the options you previously passed to `__epilot.init()`, converted to kebab-case (e.g. `topBar` becomes `top-bar`, `scrollToTop` becomes `scroll-to-top`). From fc0d0980d778d10bbb2f1cb882dccafd26569587 Mon Sep 17 00:00:00 2001 From: Adeola Adeyemo Date: Thu, 26 Feb 2026 16:19:07 +0000 Subject: [PATCH 2/4] chore: update docs with newer changes Signed-off-by: Adeola Adeyemo --- docs/journeys/web-components.md | 90 +++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/docs/journeys/web-components.md b/docs/journeys/web-components.md index 63b7d2cc..9284ccac 100644 --- a/docs/journeys/web-components.md +++ b/docs/journeys/web-components.md @@ -29,6 +29,16 @@ Place the following script tag in your page, preferably within the `` sect > ``` +For Canary updates, use the canary script + +```html title="Canary Embed script" + +``` + Loading the script with `async` ensures it downloads without blocking your page and executes as soon as it's available. The script auto-registers the `` custom element on load. ### 2. Add the Journey element @@ -59,12 +69,13 @@ All attributes are set as standard HTML attributes on the `` ele | `journey-id` | `string` | — | **Required.** The ID of the Journey to render. | | `mode` | `"inline"` \| `"full-screen"` | `"full-screen"` | The display mode. `inline` renders the Journey within the page flow. `full-screen` renders it as an overlay. | | `lang` | `"de"` \| `"en"` \| `"fr"` | `"de"` | Overrides the UI language. This affects UI labels and copy, but does not automatically translate static content configured in the Journey Builder. | -| `top-bar` | `"true"` \| `"false"` | `"false"` | Whether to show the top navigation bar. | +| `top-bar` | `"true"` \| `"false"` | `"true"` | Whether to show the top navigation bar. | | `scroll-to-top` | `"true"` \| `"false"` | `"true"` | Whether to scroll the page to the top of the Journey when the user navigates to a new step. | | `close-button` | `"true"` \| `"false"` | `"true"` | Whether to show the close button in the top bar. | | `context-data` | JSON string | — | Additional contextual data passed to the Journey and included with the submission. Must be a JSON-encoded string of key-value pairs. See [Context Data](#context-data). | | `data-injection-options` | JSON string | — | Pre-fill Journey fields and control the starting step. Must be a JSON-encoded string. See [Data Injection](#data-injection). | | `journey-token` | `string` | — | A JWT token used for [post-qualification Journeys](./post-qualification). | +| `is-full-screen-entered` | `"true"` \| `"false"` | `"false"` | Controls whether a full-screen Journey is visible. Set to `"true"` to open it. Only applies when `mode` is `"full-screen"`. | | `is-embedded` | `"true"` \| `"false"` | `"false"` | Indicates the Journey is embedded on a host app. | | `debug` | `"true"` \| `"false"` | `"false"` | Enables debug mode for development and troubleshooting. | @@ -86,7 +97,7 @@ Render the Journey directly within the page flow: ### Full-Screen Mode -In full-screen mode, the Journey does not open automatically. You need to post a message to the window to trigger it: +In full-screen mode, the Journey is hidden by default. Use the `is-full-screen-entered` attribute to control its visibility: ```html title="Full-screen mode" function openJourney() { - window.postMessage( - { - type: 'EPILOT/ENTER_FULLSCREEN', - journeyId: '', - }, - '*' - ) + const el = document.querySelector('epilot-journey') + el.setAttribute('is-full-screen-entered', 'true') } ``` -To close the Journey programmatically, post an `EPILOT/EXIT_FULLSCREEN` message in the same way: +To close the Journey, set the attribute back to `"false"`: ```javascript title="Closing the Journey" -window.postMessage( - { - type: 'EPILOT/EXIT_FULLSCREEN', - journeyId: '', - }, - '*' -) +document + .querySelector('epilot-journey') + .setAttribute('is-full-screen-entered', 'false') ``` -### Multiple Journeys +:::info Live Examples + +Interactive examples are available at [Storybook Examples](https://embed.journey.epilot.io/stories/?path=/story/next-web-component-inline--inline) for only **Public Journeys**, where you can browse different embedding scenarios and configurations. + +::: + +## Limitations + +### Single instance per page + +Only one `` element is supported per page. Placing multiple instances on the same page is not supported and may lead to unexpected behavior. -You can embed multiple Journeys on the same page. Each one operates independently: +To load a different Journey, update the attributes on the existing element rather than adding a new one: -```html title="Multiple journeys" +```html title="Single element" - -``` - -:::info Live Examples + -Interactive examples are available at `{{embed URL}}/stories`, where you can browse different embedding scenarios and configurations. + +``` -::: +If you need multiple Journeys visible simultaneously, use the [iframe embedding](./embedding) approach instead. ## Context Data @@ -262,12 +274,24 @@ document.querySelector('epilot-journey').refresh() ## Content-Security-Policy (CSP) -If your website uses a Content-Security-Policy, you will need to allow epilot domains. Since Web Components don't use iframes, you only need the `script-src` rule — the `frame-src` rule from the [Content-Security-Policy](./content-security-policy) page is not required: +If you don’t have Content-Security-Policy defined for your pages, you can skip this. If you have but can temporarily disable to perform the this test, go for that. Otherwise, please ensure you update your policy to allow the below ```text title="Minimum CSP for Web Components" -script-src 'self' https://*.epilot.io https://*.epilot.cloud; + script-src https://journey.epilot.io; + style-src 'unsafe-inline' https://journey.epilot.io https://fonts.googleapis.com; + img-src data: blob: https://file.sls.epilot.io https://file-preview.sls.epilot.io https://journey.epilot.io; + font-src data: https://journey.epilot.io https://fonts.gstatic.com; + connect-src 'self' https://*.sls.epilot.io https://*.epilot.io https://portal.epilot.cloud https://epilot-dev-user-content.s3.eu-central-1.amazonaws.com; + frame-src https://journey.epilot.io https://portal.epilot.cloud; + form-action https://submission.sls.epilot.io https://journey.epilot.io; ``` +:::tip + +These rules are subject to change as we’re rolling out new features and web components themselves. Depending on your Journey setups, you might also need to give additional permissions in case you’re using third-party apps or apps of your own. + +::: + See the dedicated [Content-Security-Policy](./content-security-policy) page for additional guidance on nonces and inline script handling. ## Migrating from iframes @@ -278,7 +302,7 @@ If you are currently embedding Journeys using iframes with the `__epilot` embed ```diff - - + + + ``` 2. **Replace the initialization code** — instead of calling `__epilot.init()`, use the `` custom element directly: From 07f3ef074a9077b560196216bd49d991b31ecbf9 Mon Sep 17 00:00:00 2001 From: Adeola Adeyemo Date: Fri, 27 Feb 2026 10:33:27 +0000 Subject: [PATCH 3/4] chore: update stories link Signed-off-by: Adeola Adeyemo --- docs/journeys/web-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/journeys/web-components.md b/docs/journeys/web-components.md index 9284ccac..ae65dd4b 100644 --- a/docs/journeys/web-components.md +++ b/docs/journeys/web-components.md @@ -128,7 +128,7 @@ document :::info Live Examples -Interactive examples are available at [Storybook Examples](https://embed.journey.epilot.io/stories/?path=/story/next-web-component-inline--inline) for only **Public Journeys**, where you can browse different embedding scenarios and configurations. +Interactive examples are available at [Storybook Examples](https://embed.journey.epilot.io/stories/?path=/docs/next-web-component--docs) for only **Public Journeys**, where you can browse different embedding scenarios and configurations. ::: From 9916b4385e7a6f44b2de05116c565207231d3bd7 Mon Sep 17 00:00:00 2001 From: Adeola Adeyemo Date: Fri, 27 Feb 2026 10:34:20 +0000 Subject: [PATCH 4/4] chore: update docs Signed-off-by: Adeola Adeyemo --- docs/journeys/web-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/journeys/web-components.md b/docs/journeys/web-components.md index ae65dd4b..e0685403 100644 --- a/docs/journeys/web-components.md +++ b/docs/journeys/web-components.md @@ -128,7 +128,7 @@ document :::info Live Examples -Interactive examples are available at [Storybook Examples](https://embed.journey.epilot.io/stories/?path=/docs/next-web-component--docs) for only **Public Journeys**, where you can browse different embedding scenarios and configurations. +Interactive examples are available at [Storybook Examples](https://embed.journey.epilot.io/stories/?path=/docs/next-web-component--docs) for only **Public Journeys**, where you can browse different embedding scenarios and configurations. Remember to update the controls section with your own parameters (journey-id, top-bar etc.) to see it in action. :::