# Selection Guide UI Plugin

The Selection Guide UI is a lightweight, zero-dependency JavaScript widget that renders size recommendations directly on your product detail pages. It fetches data from the [Size Recommender API](https://docs.parcellab.com/docs/developers/size-recommender/size-recommender/api) and displays fit category, a visual scale, confidence score, and an AI-generated customer feedback summary. The widget also supports localized default strings, configurable fallbacks for missing data, and per-section visibility controls.

This is an **open-source reference implementation** in the [parcelLab Embedded UI Snippets repository](https://github.com/parcelLab/parcellab-embedded-ui-snippets/tree/main/packages/selection-guide-ui). Use it as-is, or as a starting point for building your own custom integration against the API.

**Sample with short info text**

|                                                                                                                                                                                                                                                                                                   |                                                                                                                                                                                                                                                                                 |
| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| ![Short text, neutral color, comfortable spacing, inline display](https://1242524681-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Few6OnyRUe6InzC96WnMr%2Fuploads%2Fgit-blob-c6ea2c3334a7d14c42c783a0b4a2eb0e13489d1f%2Fshorttext_neutral_comfortable_inline.png?alt=media) | ![Short text, colored, compact spacing, card display](https://1242524681-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Few6OnyRUe6InzC96WnMr%2Fuploads%2Fgit-blob-c235af9ef18f0b0e0faf614f49ea25d31bd957d9%2Fshorttext_colored_compact_card.png?alt=media) |
|                                                                                                                         neutral color, comfortable spacing, inline display                                                                                                                        |                                                                                                                      colored, compact spacing, card display                                                                                                                     |

**Sample with longer info text**

|                                                                                                                                                                                                                                                                                         |                                                                                                                                                                                                                                                                               |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| ![Long text, neutral color, compact spacing, inline display](https://1242524681-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Few6OnyRUe6InzC96WnMr%2Fuploads%2Fgit-blob-0b342c5284a465ac4ec6d1fbbb554dd2a32cfdb8%2Flongtext_neutral_compact_inline.png?alt=media) | ![Long text, colored, compact spacing, card display](https://1242524681-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Few6OnyRUe6InzC96WnMr%2Fuploads%2Fgit-blob-7a1cc45b1634640b641a12351b99debcc6101b75%2Flongtext_colored_compact_card.png?alt=media) |
|                                                                                                                      neutral color, compact spacing, inline display                                                                                                                     |                                                                                                                     colored, compact spacing, card display                                                                                                                    |

**Missing data**

|                                                                                                                                                                                                                                                         |                                                                                                                                                                                                                                                            |
| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| ![Empty state with default fit info](https://1242524681-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Few6OnyRUe6InzC96WnMr%2Fuploads%2Fgit-blob-50b3204c3bd323273649f11d7a853074574ba58f%2Femptystate_show-default.png?alt=media) | ![Empty state with missing data notice](https://1242524681-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Few6OnyRUe6InzC96WnMr%2Fuploads%2Fgit-blob-6e1ca7c02d03912e1613fcb7af70121844f6e4bf%2Femptystate_show-missing.png?alt=media) |
|                                                                                                 `notFoundMode: 'true-to-size'` — shows default fit info                                                                                                 |                                                                                                     `notFoundMode: 'empty'` — shows missing data notice                                                                                                    |

## Installation

The widget ships as a standalone JavaScript bundle. No build tools or package managers are required.

Available bundle files:

* `https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.iife.js`
* `https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.esm.js`

{% tabs %}
{% tab title="Script tag (recommended)" %}
Add a single `<script>` tag to your page. The IIFE build auto-initializes any element with the `data-size-recommender` attribute:

```html
<div
  data-size-recommender
  data-account-id="YOUR_ACCOUNT_ID"
  data-product-id="YOUR_PRODUCT_ID"
  data-not-found-mode="true-to-size"
></div>

<script
  src="https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.iife.js"
  defer
></script>
```

{% endtab %}

{% tab title="JavaScript API" %}
For more control, use the JavaScript API to initialize the widget programmatically:

```html
<div id="size-recommender"></div>

<script src="https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.iife.js"></script>
<script>
  const widget = window.SizeRecommender.init({
    target: '#size-recommender',
    accountId: 'YOUR_ACCOUNT_ID',
    productId: 'YOUR_PRODUCT_ID',
    notFoundMode: 'true-to-size'
  });
</script>
```

{% endtab %}

{% tab title="ES module" %}
If you want to load the ESM build directly in the browser, import it from the CDN:

```html
<div id="size-recommender"></div>

<script type="module">
  import { init } from 'https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.esm.js';

  const widget = init({
    target: '#size-recommender',
    accountId: 'YOUR_ACCOUNT_ID',
    productId: 'YOUR_PRODUCT_ID',
    notFoundMode: 'true-to-size'
  });
</script>
```

{% endtab %}
{% endtabs %}

## Live demo

Try the interactive demo to preview different configurations and copy embed code:

{% embed url="<https://cdn.parcellab.com/playground/selection-guide-ui/index.html>" %}

The demo page is maintained in the [Selection Guide UI module](https://github.com/parcelLab/parcellab-embedded-ui-snippets/tree/main/packages/selection-guide-ui) in the parcelLab Embedded UI Snippets repository.

## Configuration

All options can be set via JavaScript or as HTML `data-*` attributes.

| Option               | Data attribute             | Type                                    | Default                       | Description                                                                                                            |
| -------------------- | -------------------------- | --------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `target`             | —                          | `string \| HTMLElement`                 | —                             | **Required** (JS only). CSS selector or DOM element to mount the widget.                                               |
| `accountId`          | `data-account-id`          | `number \| string`                      | —                             | **Required**. Your parcelLab account ID.                                                                               |
| `productId`          | `data-product-id`          | `string`                                | —                             | **Required**. Product identifier passed to the API.                                                                    |
| `articleName`        | `data-article-name`        | `string`                                | —                             | Legacy alias for `productId`. Still accepted for backwards compatibility.                                              |
| `notFoundMode`       | `data-not-found-mode`      | `'empty' \| 'true-to-size' \| 'hidden'` | `'true-to-size'`              | Behavior when no recommendation exists (see [404 handling](#404-handling)).                                            |
| `appearance`         | `data-appearance`          | `'neutral' \| 'colored' \| 'alert'`     | `'colored'`                   | Visual style. `neutral` is grayscale, `colored` uses a gradient track, and `alert` uses stronger fit-sensitive colors. |
| `density`            | `data-density`             | `'compact' \| 'comfortable'`            | `'comfortable'`               | Spacing. `compact` is ideal for tighter PDP layouts.                                                                   |
| `surface`            | `data-surface`             | `'subtle' \| 'plain'`                   | `'plain'`                     | `subtle` renders a light card background; `plain` renders inline.                                                      |
| `locale`             | `data-locale`              | `string`                                | `'en'`                        | Locale for default message strings. Supported locales: `en`, `de`, `fr`, `it`, `es`.                                   |
| `showPill`           | `data-show-pill`           | `boolean`                               | `true`                        | Show or hide the fit category pill badge.                                                                              |
| `showScale`          | `data-show-scale`          | `boolean`                               | `true`                        | Show or hide the fit scale.                                                                                            |
| `showRecommendation` | `data-show-recommendation` | `boolean`                               | `true`                        | Show or hide the recommendation callout block.                                                                         |
| `showSummary`        | `data-show-summary`        | `boolean`                               | `true`                        | Show or hide the AI-generated summary inside the recommendation block.                                                 |
| `messages`           | `data-messages`            | `Partial<WidgetMessages>`               | —                             | Override any default text (title, labels, headings). Pass as JSON string in HTML.                                      |
| `theme`              | `data-theme`               | `Partial<WidgetTheme>`                  | —                             | Override CSS tokens (colors, radius). Pass as JSON string in HTML.                                                     |
| `className`          | `data-class-name`          | `string`                                | —                             | Extra CSS classes added to the root element.                                                                           |
| `apiBaseUrl`         | `data-api-base-url`        | `string`                                | `'https://api.parcellab.com'` | Override the API base URL (for testing or staging).                                                                    |

{% hint style="info" %}
The legacy `articleName` / `data-article-name` option is still accepted as an alias for `productId`, but `productId` is recommended for new integrations.
{% endhint %}

### HTML attribute example

When using the auto-initializing script tag, configure the widget directly on the target element:

```html
<div
  data-size-recommender
  data-account-id="YOUR_ACCOUNT_ID"
  data-product-id="YOUR_PRODUCT_ID"
  data-not-found-mode="hidden"
  data-appearance="alert"
  data-density="comfortable"
  data-surface="plain"
  data-locale="de"
  data-show-summary="false"
></div>

<script
  src="https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.iife.js"
  defer
></script>
```

### Messages customization

Override any text label using the `messages` option:

```javascript
window.SizeRecommender.init({
  target: '#size-recommender',
  accountId: 'YOUR_ACCOUNT_ID',
  productId: 'YOUR_PRODUCT_ID',
  messages: {
    title: 'How It Fits',
    recommendationHeadingSmall: 'Consider sizing up',
    recommendationHeadingLarge: 'Consider sizing down',
    recommendationHeadingTrue: 'Should fit as expected',
    confidenceText: '{value}% confident based on store feedback'
  }
});
```

### Theme customization

Override visual tokens to match your brand:

```javascript
window.SizeRecommender.init({
  target: '#size-recommender',
  accountId: 'YOUR_ACCOUNT_ID',
  productId: 'YOUR_PRODUCT_ID',
  theme: {
    backgroundColor: '#f6f6f6',
    textColor: '#222222',
    mutedTextColor: '#666666',
    borderColor: '#e4e4e4',
    radius: '12px'
  }
});
```

## Appearance modes

* **`neutral`** — grayscale style that blends with most page designs.
* **`colored`** (default) — uses a gradient on the fit scale and tinted badge for a more visual indication.
* **`alert`** — uses stronger fit-sensitive colors to make likely size mismatch more prominent.

Both modes are shown in the comparison table above.

## 404 handling

When the API returns no recommendation for a product, the widget supports three modes:

* **`true-to-size`** (default) — shows a "likely true to size" fallback without confidence or AI summary. Useful as a safe default assumption.
* **`empty`** — shows a "no data available" message.
* **`hidden`** — hides the widget entirely until valid data is returned.

If you use `hidden`, the widget becomes visible again automatically when a later `update()` or `refresh()` call receives valid data.

The `true-to-size` and `empty` modes are shown in the first row of the comparison table above.

## Widget instance API

The `init()` call returns a widget instance with methods for dynamic updates:

| Method                  | Description                                                                              |
| ----------------------- | ---------------------------------------------------------------------------------------- |
| `widget.update(config)` | Update configuration (e.g., switch product) and re-fetch. Cancels any in-flight request. |
| `widget.refresh()`      | Re-fetch the recommendation with current configuration.                                  |
| `widget.destroy()`      | Remove the widget from the DOM and clean up event listeners.                             |

### Example: switching products

On single-page applications (SPAs) or pages with product variant selectors, update the widget when the product changes:

```javascript
const widget = window.SizeRecommender.init({
  target: '#size-recommender',
  accountId: 'YOUR_ACCOUNT_ID',
  productId: 'Original Product'
});

// When the user selects a different variant:
document.querySelector('#variant-select').addEventListener('change', (e) => {
  widget.update({ productId: e.target.value });
});
```

## Styling

The widget renders in the **light DOM** (not Shadow DOM), so your page's typography inherits naturally. You can target the widget's elements directly with CSS.

### CSS classes

The widget uses [BEM-style](https://getbem.com/) class names under the `.pl-size-recommender` namespace. All classes are applied in the light DOM, so you can target them directly from your stylesheet.

#### Root modifier classes

These are applied to the root element and reflect the current configuration and state:

| Class                                       | Description                                         |
| ------------------------------------------- | --------------------------------------------------- |
| `.pl-size-recommender`                      | Root element (always present)                       |
| `.pl-size-recommender--neutral`             | Neutral (grayscale) appearance                      |
| `.pl-size-recommender--colored`             | Colored appearance with gradient track              |
| `.pl-size-recommender--alert`               | Alert appearance with stronger fit-sensitive colors |
| `.pl-size-recommender--density-compact`     | Compact spacing                                     |
| `.pl-size-recommender--density-comfortable` | Comfortable spacing                                 |
| `.pl-size-recommender--surface-subtle`      | Card background with border                         |
| `.pl-size-recommender--surface-plain`       | Inline, no card background                          |
| `.pl-size-recommender--state-loading`       | Widget is loading data                              |
| `.pl-size-recommender--state-ready`         | Data loaded successfully                            |
| `.pl-size-recommender--state-fallback-true` | Showing true-to-size fallback (no data)             |
| `.pl-size-recommender--state-empty`         | Showing empty/no-data state                         |
| `.pl-size-recommender--state-error`         | API error occurred                                  |
| `.pl-size-recommender--state-hidden`        | Widget is hidden because `notFoundMode` is `hidden` |
| `.pl-size-recommender--fit-small`           | Product runs small                                  |
| `.pl-size-recommender--fit-true`            | Product is true to size                             |
| `.pl-size-recommender--fit-large`           | Product runs large                                  |
| `.pl-size-recommender--fit-unknown`         | Fit category unknown                                |

#### Element classes

These target individual parts of the widget:

| Class                                          | Description                                                             |
| ---------------------------------------------- | ----------------------------------------------------------------------- |
| `.pl-size-recommender__header`                 | Header row containing title and pill                                    |
| `.pl-size-recommender__title`                  | "How It Fits" heading                                                   |
| `.pl-size-recommender__pill`                   | Fit category badge (e.g., "True to size")                               |
| `.pl-size-recommender__scale`                  | Scale container (labels + track)                                        |
| `.pl-size-recommender__scale-labels`           | "Runs Small / True to Size / Runs Large" labels                         |
| `.pl-size-recommender__track`                  | The horizontal fit bar                                                  |
| `.pl-size-recommender__marker`                 | Position dot on the track                                               |
| `.pl-size-recommender__recommendation`         | Recommendation callout card                                             |
| `.pl-size-recommender__recommendation-header`  | Header row inside the recommendation                                    |
| `.pl-size-recommender__recommendation-icon`    | Fit direction icon (arrow up/down/dash)                                 |
| `.pl-size-recommender__recommendation-title`   | Recommendation heading (e.g., "Consider sizing up")                     |
| `.pl-size-recommender__recommendation-meta`    | Confidence text (e.g., "89% confident based on real customer feedback") |
| `.pl-size-recommender__recommendation-summary` | AI-generated customer feedback summary                                  |

#### Hiding elements with CSS

If you want to hide specific parts of the widget, prefer the built-in visibility options (`showPill`, `showScale`, `showRecommendation`, `showSummary`). You can also use CSS and `display: none` on the relevant class:

```css
/* Hide the confidence score */
.pl-size-recommender__recommendation-meta {
  display: none;
}

/* Hide the AI summary text */
.pl-size-recommender__recommendation-summary {
  display: none;
}

/* Hide the fit category pill badge */
.pl-size-recommender__pill {
  display: none;
}

/* Hide the entire scale bar */
.pl-size-recommender__scale {
  display: none;
}

/* Hide the widget entirely when it enters the hidden state */
.pl-size-recommender--state-hidden {
  display: none;
}
```

### CSS variables

Override these on `.pl-size-recommender` or any ancestor element:

| Variable                                  | Description                                     |
| ----------------------------------------- | ----------------------------------------------- |
| `--plsr-background`                       | Widget background color                         |
| `--plsr-recommendation-background`        | Recommendation callout background               |
| `--plsr-border`                           | Border color                                    |
| `--plsr-text`                             | Primary text color                              |
| `--plsr-muted-text`                       | Secondary text color                            |
| `--plsr-accent`                           | Accent color for highlights                     |
| `--plsr-badge-background`                 | Fit category badge background                   |
| `--plsr-badge-text`                       | Fit category badge text color                   |
| `--plsr-track`                            | Scale track color (neutral mode)                |
| `--plsr-track-start` / `--plsr-track-end` | Track gradient colors (colored and alert modes) |
| `--plsr-radius`                           | Border radius                                   |

### Example: custom styling

```css
.pl-size-recommender {
  --plsr-background: #fafafa;
  --plsr-text: #1a1a1a;
  --plsr-accent: #3D3AD3;
  --plsr-radius: 16px;
  font-family: 'Your Brand Font', sans-serif;
}
```

## Building your own integration

This widget is an **open-source reference implementation**. If you need deeper customization beyond what the configuration options offer, you have several paths:

1. **Use the API directly** — Call the [Size Recommender API](https://docs.parcellab.com/docs/developers/size-recommender/size-recommender/api) from your own frontend code and render the response however you like.
2. **Fork the embedded UI snippets repository** — Start from the Selection Guide UI module and customize the rendering, styling, and behavior to match your exact requirements.
3. **Use as a library** — Import the ESM build and override messages, theme, and CSS to fit your design system.

The [source code](https://github.com/parcelLab/parcellab-embedded-ui-snippets/tree/main/packages/selection-guide-ui) is organized into clear modules (API client, config resolution, model transformation, rendering) that you can reference or reuse.

## Source code

* **Repository:** [github.com/parcelLab/parcellab-embedded-ui-snippets/tree/main/packages/selection-guide-ui](https://github.com/parcelLab/parcellab-embedded-ui-snippets/tree/main/packages/selection-guide-ui)
* **Live demo:** [cdn.parcellab.com/playground/selection-guide-ui](https://cdn.parcellab.com/playground/selection-guide-ui/index.html)
* **License:** MIT


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.parcellab.com/docs/developers/size-recommender/size-recommender/ui-plugin.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
