> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firmhouse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shared page components

> Reference for Liquid tags shared across authenticated Customer Portal page templates.

These tags are reused across multiple page templates.

## `{% component 'component_key' %}`

Renders the first enabled variant whose conditions match the current subscription. The component must exist in the same project as the template.

Used in: Dashboard, Orders, Order details, Catalog, Offer, Offer confirmation, Other pages, Cancellation reasons, Cancellation follow-up, and Subscription profile

```liquid theme={null}
{% component 'cancellation_reassurance' %}
```

Manage component variants under **Customer Portal → Components**. When no enabled variant matches, the tag renders nothing outside the visual editor.

## `{% workflow id: 44 %}`

Loads a Workflow Builder workflow into a Liquid variable without rendering markup. The variable is available only when the workflow has a published version; in the visual editor, the current draft is available for preview. Use its configured inputs to show products or other workflow details without copying them into the template.

Used in: Dashboard, Orders, Order details, Catalog, Offer, Offer confirmation, Other pages, Cancellation reasons, Cancellation follow-up, and Subscription profile

| Parameter | Type    | Default      |
| --------- | ------- | ------------ |
| `id`      | Integer | None         |
| `as`      | String  | `"workflow"` |

```liquid theme={null}
{% workflow id: 44 %}
{% if workflow %}
  {% for input in workflow.inputs %}
    {% if input.product %}
      <span>{{ input.product.title }}</span>
    {% endif %}
  {% endfor %}
{% endif %}
```

## `{% legacy_navbar %}`

Shared top navigation.

Used in: Dashboard, Orders, Order details, Catalog, Offer, Offer confirmation, Subscription profile, Other pages, Cancellation reasons, and Cancellation follow-up

| Parameter            | Type    | Default                                  |
| -------------------- | ------- | ---------------------------------------- |
| `navbar_classes`     | String  | `"bg-gray-900 border-b border-gray-700"` |
| `link_classes`       | String  | `"text-white"`                           |
| `link_hover_classes` | String  | `"hover:text-white hover:opacity-100"`   |
| `show_invoices`      | Boolean | `false`                                  |

```liquid theme={null}
{% legacy_navbar link_classes: "text-gray-900 text-sm font-medium" %}
```

The invoices overview is hidden by default. Set `show_invoices` to include it in the navigation:

```liquid theme={null}
{% legacy_navbar show_invoices: true %}
```

```html theme={null}
<div class="bg-gray-900 text-white text-sm">
  <nav class="flex items-center justify-between p-4">
    <a href="/self-service" class="font-semibold">Subscription</a>
    <div class="flex gap-4">
      <a href="/self-service/orders">Orders</a>
      <a href="/self-service/invoices">Invoices</a>
      <button type="button">Logout</button>
    </div>
  </nav>
</div>
```

## `{% shopify_storefront_access_token %}`

Outputs the project's Shopify Storefront API public access token. Use this to make client-side requests to the Shopify Storefront GraphQL API, for example to fetch product data or build custom product browsing experiences.

Returns an empty string when the Shopify subscriptions app is not configured for the project.

The token is cached for 1 hour to avoid repeated Shopify Admin API calls.

Used in: Dashboard, Orders, Order details, Catalog, Offer, Offer confirmation, Subscription profile, Other pages, Cancellation reasons, Cancellation follow-up, and Shared head

```liquid theme={null}
<script>
  window.shopifyStorefrontToken = "{% shopify_storefront_access_token %}";
</script>
```

## `{% shopify_store_domain %}`

Outputs the Shopify store domain (for example `my-store.myshopify.com`) configured for the Shopify app. Use this to build Shopify Storefront API endpoints or other store-specific URLs directly in your templates.

Returns an empty string when the Shopify app is not configured for the project.

Used in: Dashboard, Orders, Order details, Catalog, Offer, Offer confirmation, Subscription profile, Other pages, Cancellation reasons, Cancellation follow-up, and Shared head

```liquid theme={null}
<script>
  const shopifyDomain = "{% shopify_store_domain %}";
  const storefrontToken = "{% shopify_storefront_access_token %}";
  const storefrontEndpoint = `https://${shopifyDomain}/api/2026-01/graphql.json`;

  fetch(storefrontEndpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Storefront-Access-Token": storefrontToken
    },
    body: JSON.stringify({
      query: `{
        products(first: 10) {
          edges {
            node {
              id
              title
              handle
            }
          }
        }
      }`
    })
  })
    .then(res => res.json())
    .then(data => console.log(data));
</script>
```

## `{% slide_out_pane %} ... {% endslide_out_pane %}`

Reusable slide-out pane for custom overlays across Customer Portal templates.

Used in: Dashboard, Orders, Order details, Catalog, Offer, Offer confirmation, Subscription profile, Other pages, Cancellation reasons, and Cancellation follow-up

| Parameter              | Type                          | Default            |
| ---------------------- | ----------------------------- | ------------------ |
| `slide_from`           | String (`"right"`/`"bottom"`) | `"right"`          |
| `pane_id`              | String                        | `"slide-out-pane"` |
| `slide_out_percentage` | String (`"10"` ... `"90"`)    | `"40"`             |

```liquid theme={null}
{% slide_out_pane slide_from: "right", slide_out_percentage: "40", pane_id: "product-info-pane" %}
  <div id="product-info-content">Select a product to see details.</div>
{% endslide_out_pane %}
```

Manual API (no custom events required):

```html theme={null}
<script>
  window.sscSlideOutPane.open("product-info-pane", { productId: "123" });
  window.sscSlideOutPane.close("product-info-pane");
  window.sscSlideOutPane.toggle("product-info-pane");
  const isOpen = window.sscSlideOutPane.isOpen("product-info-pane");
</script>
```

* `pane_id` maps to the pane DOM `id`.
* If omitted in API calls, the first registered slide-out pane is used.

## `{% subscription_files %}`

Lists files attached to the subscription that are visible to the customer. The component renders nothing when there are no customer-visible files.

Used in: Dashboard and Subscription profile

This component has no parameters.

```liquid theme={null}
{% subscription_files %}
```

```html theme={null}
<div class="bg-white border border-gray-200 rounded-xl p-6">
  <h2 class="text-xl font-semibold text-gray-900 mb-4">Files</h2>
  <ul class="divide-y divide-gray-200">
    <li class="py-3">
      <a href="/self-service/subscription_files/123">Rental agreement.pdf</a>
      <p class="mt-1 text-sm text-gray-500">128 KB</p>
    </li>
  </ul>
</div>
```

## Translation Filter: `| t`

Use `| t` to translate strings from the `self_service_center` i18n namespace.

```liquid theme={null}
{{ 'dashboard.cancel_subscription' | t }}
{{ 'churn_requests.skip_next_order.skip_orders' | t: count: 2 }}
{{ 'dashboard.cancel_subscription' | t: locale: 'nl' }}
{{ 'dashboard.missing_key' | t: default: 'Cancel subscription' }}
```

* Keys are resolved under `self_service_center` (for example, `dashboard.cancel_subscription` maps to `self_service_center.dashboard.cancel_subscription`).
* `locale` is optional; when omitted, the current request locale is used.
* `default` is optional; when present, it is used as fallback for missing translations.
* If a translation key is missing and no `default` is provided, the original key string is returned.
* If required interpolation data is missing, the filter returns the original key with the missing argument name (for example, `churn_requests.skip_next_order.skip_orders (missing interpolation: count)`).

Interpolation requirement example:

```liquid theme={null}
{{ 'churn_requests.skip_next_order.skip_orders' | t }}
{{ 'churn_requests.skip_next_order.skip_orders' | t: count: 2 }}
```
