# Pages

Template pages define which sections appear on each page of your storefront. Every page is a separate `.ts` file inside the `pages/` directory of your template.

```
my-template/
├── configuration.ts
└── pages/
    ├── home.ts          # HOME page
    ├── product.ts       # PRODUCT storefront page
    ├── catalog.ts       # CATALOG storefront page
    ├── category.ts      # CATEGORY storefront page
    └── about.ts         # CUSTOM page
```

Full code example:

```typescript
import { template, section } from '@lightspeed/crane-api';

export default template.page({
  sections: [
    section.default({
      id: 'slider',
      showcase_id: '001',
    }),
    section.custom({
      id: 'hero-banner',
      showcase_id: '1',
    }),
    section.custom({
      id: 'featured-products',
      showcase_id: '1',
    }),
  ],
});
```

Each page file must default-export the result of the `template.page()` factory from `@lightspeed/crane-api`. The file name determines the page type.

### Page Types <a href="#page-types" id="page-types"></a>

The file name (without extension) maps to one of the built-in page types. Names that do not match a reserved name are treated as custom pages.

| File name      | Page type  | Description                                |
| -------------- | ---------- | ------------------------------------------ |
| `home.ts`      | `HOME`     | The storefront home page                   |
| `product.ts`   | `PRODUCT`  | Product detail pages (storefront page)     |
| `catalog.ts`   | `CATALOG`  | The product catalog page (storefront page) |
| `category.ts`  | `CATEGORY` | Category listing pages (storefront page)   |
| Any other name | `CUSTOM`   | A custom page defined by your template     |

{% hint style="info" %}
**Storefront pages**

`PRODUCT`, `CATALOG`, and `CATEGORY` are **storefront pages**. They have special constraints — see [Validation Errors](#validation-errors) below.
{% endhint %}

### Factory Functions <a href="#factory-functions" id="factory-functions"></a>

The `@lightspeed/crane-api` package exports the following factory functions used in page files:

| Factory             | Description                                                                                                       |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `template.page()`   | Creates a page configuration object with full type safety. Accepts `sections` and optionally `metadata`.          |
| `section.default()` | Creates a default section referencing a pre-defined Lightspeed section. Sets `type` to `'default'` automatically. |
| `section.custom()`  | Creates a custom section referencing your own section implementation. Sets `type` to `'custom'` automatically.    |
| `section.store()`   | Creates a storefront section placeholder. Sets `type` to `'store'` automatically.                                 |

{% hint style="info" %}
**Recommended**

Using factory functions is recommended over plain objects. They provide type safety and automatically set the `type` discriminator field for you.
{% endhint %}

### Properties <a href="#properties" id="properties"></a>

The page configuration object has the following properties:

| Property   | Required    | Description                                             |
| ---------- | ----------- | ------------------------------------------------------- |
| `sections` | Yes         | Array of sections displayed on this page                |
| `metadata` | Conditional | Required for `CUSTOM` pages, must be omitted for others |

#### `metadata` <a href="#metadata" id="metadata"></a>

Only used on custom pages. Provides display information for the page.

| Property | Required | Description                        |
| -------- | -------- | ---------------------------------- |
| `title`  | Yes      | Display title of the page (string) |

<details>

<summary>Code example</summary>

```typescript
import { template } from '@lightspeed/crane-api';

export default template.page({
  metadata: {
    title: 'About Us',
  },
  sections: [],
});
```

</details>

#### `sections` <a href="#sections" id="sections"></a>

An array of section objects. Each section must be one of three types: **default**, **custom**, or **store**.

**Default Section**

References a pre-defined Lightspeed section.

| Property      | Required | Description                                                                                             |
| ------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `type`        | Auto     | Set automatically by `section.default()`                                                                |
| `id`          | Yes      | Must match a default section name, optionally suffixed with `_XXX` where `XXX` is three digits (string) |
| `showcase_id` | No       | Three-digit showcase identifier (string)                                                                |

#### Default section list

| ID                          | Description               |
| --------------------------- | ------------------------- |
| `header`                    | Site header               |
| `footer`                    | Site footer               |
| `cover`                     | Cover image / hero banner |
| `announcement_bar`          | Announcement bar          |
| `slider`                    | Image slider / carousel   |
| `special_offer`             | Special offer / promotion |
| `customer_review`           | Customer reviews          |
| `company_info`              | Company information       |
| `shipping_payment`          | Shipping and payment info |
| `location`                  | Store location / map      |
| `store`                     | Store product listing     |
| `video`                     | Video embed               |
| `image_gallery`             | Image gallery             |
| `contact_info`              | Contact information       |
| `contacts_widget_whatsapp`  | WhatsApp contact widget   |
| `contacts_widget_instagram` | Instagram contact widget  |
| `contacts_widget_facebook`  | Facebook contact widget   |
| `contacts_widget_phone`     | Phone contact widget      |

To use multiple instances of the same default section, append `_XXX` (three digits) to the ID, e.g., `slider_001`, `slider_002`.

{% hint style="info" %}
**Discoverability**

Use your editor's autocompletion on the `id` field of `section.default()` to discover all valid values.
{% endhint %}

**Custom Section**

References one of your own section implementations.

| Property             | Required | Description                                                          |
| -------------------- | -------- | -------------------------------------------------------------------- |
| `type`               | Auto     | Set automatically by `section.custom()`                              |
| `id`                 | Yes      | Identifier matching a section in your `sections/` directory (string) |
| `showcase_id`        | No       | Showcase identifier (string)                                         |
| `showcase_overrides` | No       | Override showcase content and design values (object)                 |
| `category`           | No       | Category for collection sections (string)                            |

**Store Section**

A placeholder for storefront-managed content. Used exclusively on storefront pages.

| Property | Required | Description                            |
| -------- | -------- | -------------------------------------- |
| `type`   | Auto     | Set automatically by `section.store()` |
| `id`     | No       | Optional identifier (string)           |

<details>

<summary>Code example</summary>

```typescript
import { template, section } from '@lightspeed/crane-api';

export default template.page({
  sections: [
    section.store(),
  ],
});
```

</details>

### Validation Errors <a href="#validation-errors" id="validation-errors"></a>

Crane validates your page files during the build step. Below are the errors you may encounter and how to resolve them.

#### Storefront Page Errors <a href="#storefront-page-errors" id="storefront-page-errors"></a>

Storefront pages (`PRODUCT`, `CATALOG`, `CATEGORY`) follow strict rules: the `sections` array must contain **exactly one** section of type `store`.

| Error                                                 | Cause                                          | Resolution                                 |
| ----------------------------------------------------- | ---------------------------------------------- | ------------------------------------------ |
| `sections must contain at least one section`          | `sections` array is empty on a storefront page | Add a `section.store()` entry              |
| `Page type "..." must have exactly one section`       | Storefront page has more than one section      | Keep only one `section.store()` entry      |
| `Page type "..." must have a section of type "store"` | Storefront page section is not of type `store` | Replace the section with `section.store()` |

#### Non-Storefront Page Errors <a href="#non-storefront-page-errors" id="non-storefront-page-errors"></a>

Non-storefront pages (`HOME`, `CUSTOM`) cannot contain `store` sections and must not use `'header'` or `'footer'` as section ids (those belong in `configuration.ts`).

| Error                                                             | Cause                                               | Resolution                                                 |
| ----------------------------------------------------------------- | --------------------------------------------------- | ---------------------------------------------------------- |
| `Page type "..." cannot contain store sections`                   | Non-storefront page contains a `store` section      | Remove the `store` section or move it to a storefront page |
| `Section "header" or "footer" is not allowed among page sections` | A section uses `'header'` or `'footer'` as its `id` | Move header/footer sections to `configuration.ts`          |

#### Metadata Errors <a href="#metadata-errors" id="metadata-errors"></a>

`CUSTOM` pages **must** include a `metadata` property with a `title`. All other page types **must not** include `metadata`.

| Error                                               | Cause                               | Resolution                             |
| --------------------------------------------------- | ----------------------------------- | -------------------------------------- |
| `Page type "CUSTOM" must have a metadata property`  | Custom page is missing `metadata`   | Add a `metadata` object with a `title` |
| `Page type "..." must not have a metadata property` | Non-custom page includes `metadata` | Remove the `metadata` property         |

#### Section Errors <a href="#section-errors" id="section-errors"></a>

| Error                                                                         | Cause                                                   | Resolution                                                                      |
| ----------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `Custom section with id "..." must exist in sections directory`               | Referenced custom section not found                     | Create the matching section in the `sections/` directory                        |
| `id must match pattern: [default_section_name] or [default_section_name]_XXX` | Default section id doesn't follow the naming convention | Use a valid default section name, optionally suffixed with `_` and three digits |
| `showcase_id must be a three digit string`                                    | `showcase_id` is not three digits                       | Use a three-digit string like `'001'`                                           |

#### Schema Errors <a href="#schema-errors" id="schema-errors"></a>

| Error                           | Cause                               | Resolution                                  |
| ------------------------------- | ----------------------------------- | ------------------------------------------- |
| `Unrecognized key(s) in object` | Extra properties in the page object | Remove properties not defined in the schema |

{% hint style="warning" %}
**Strict Mode**

The page schema uses strict mode. Only documented properties are allowed — any extra fields will cause a validation error.
{% endhint %}


---

# 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.ecwid.com/site-themes/develop-site-themes/templates/pages.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.
