> ## 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.

# Common components

> Reference for Liquid tags shared across all Customer Portal templates, including subscription, customer, and product data available on every page.

These tags are reused across multiple page templates.

## `{% legacy_navbar %}`

Shared top navigation.

Used in: All templates

| 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"`   |

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

```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: All templates

```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: All templates

```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: All templates

| 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 }}
```
