Skip to content

Page JSON Structure

Mehrdad Pajuhaan edited this page Oct 23, 2026 · 1 revision

Page JSON Structure

Selldone pages are plain JSON. The editor writes it, the viewer reads it, and your server stores it as the page's content. This page documents the structure as implemented in Builder.ts, src/section/section.ts and models/element/LModelElement.ts, so you can store, inspect, migrate or generate pages safely.

The big picture

Page model (from @selldone/core-js)
├── title, description, image, direction ("ltr" | "rtl" | "auto"), ...
├── content                 ← what the builder exports
│   ├── title
│   ├── style               ← page-wide typography and background
│   └── sections[]          ← ordered list of sections
│       └── { uid, label, object }
│                              └── element tree (XSection → XContainer → XRow → XColumn → ...)
└── css                     ← optional custom CSS { classes[], raw }

$builder.export() returns { title, sections, style }. $builder.loadPage({ content, css, direction }) loads it back.

Content

Key Type Description
title string Optional title stored with the content.
style object Page-wide style (see below).
sections array Sections in display order.

Sections

{
  "uid": "auto_48213301275",
  "label": "Horizontal Hero",
  "object": { "component": "XSection", "...": "..." }
}
Key Description
uid Unique section id. If missing, the builder generates one (auto_ + random number). It is also used as the DOM id of the rendered section.
label Human-readable name shown in the editor. Defaults to Section.
object Root element of the section, normally an XSection.

Legacy (v1) sections use name and data instead of object. They are converted automatically when loaded (see Migration).

Elements

Every element in the tree has the same shape (LModelElement.toJson()):

Key Type Description
component string Element type, for example XText. Must be a registered component (list below).
id string | null Optional element id.
background object Background settings (see below).
style object Inline CSS as a JavaScript style object, for example { "paddingTop": "24px" }.
classes string[] CSS classes, for example Vuetify utility classes such as mb-2 or text-center.
data object Element-specific data (see examples).
props object | null Extra properties.
children array Child elements.
label string | null Optional label used to find specific children (for example a title inside a column).

Background

background follows LModelBackground: bg_color, bg_gradient (array of colors), bg_image, bg_size (default cover), bg_repeat, bg_position, bg_rotation (degrees), bg_custom, bg_backdrop (backdrop filters), bg_video and dark.

Components you can use in JSON

These element classes are registered in LUtilsComponents.XObjects and can be loaded from JSON:

Group Components
Layout XSection, XContainer, XRow, XColumn, XColumnImageText, XScroller
Content XText, XButton, XButtons, XUploader (image), XLottie, XMarquee, XArticle, XCode
Galleries XSwiper, XGalleryExpandable, XGalleryExpandableItem
Commerce XProduct, XProducts, XProductOverview, XFeederProducts, XSearch
Blog XFeederBlogs
Forms XForm, XInputText
Embed XEmbedPage

If a component is unknown, the loader logs LUtilsLoader | JsonObjectToInstance | Class not found! and skips that element.

Data examples

Component data
XSection { "hide": { "sm": false, "md": false, "lg": false, "xl": false, "guest": false, "user": false } }
XContainer { "fluid": false }
XRow { "align": "center", "justify": "center", "no_wrap": false, "reverse": false } — align: start, center, end, stretch, baseline; justify: start, center, end, space-around, space-between, space-evenly, stretch
XColumn { "grid": { "mobile": 12, "tablet": 6, "desktop": 4, "widescreen": null } } — values 1 to 12 or null
XText { "value": "Hello <b>world</b>", "tag": "h1" } — tag: p, h1–h6, span, div
XButton { "content": "Shop now", "href": "/products", "color": "", "size": "x-large", "variant": "elevated", "align": "center", ... }
XUploader { "src": "https://.../image.jpg", "link": null, "alt": "Product photo", "setting": { ... } }
XProducts { "align": "center", "justify": "center", "no_wrap": false, "filter": { "count": 8, "sort": "...", "only_available": true, ... } }
XCode { "code": "<div>...</div>", "mode": "html", "properties": null } — mode: html or vue

The data classes live next to each component in components/x/<name>/X<Name>ObjectData.ts. Read them for the full list of fields and defaults.

Page style

content.style holds page-wide settings. When a page is loaded, missing values get defaults:

Key Default Notes
font_size 16 Base font size.
fonts [] Google Fonts used by the page. Shop custom fonts are not stored here; pass them as customFonts.
bg_color, bg_gradient, bg_size, bg_custom, bg_repeat "", [], cover, null, null Page background.
h1_size … h6_size, p_size builder defaults Heading and paragraph sizes. Responsive variants such as h1_size_md exist in the Core Page.IStyle type.

The storefront also reads header options from the style: menu_transparent, menu_dark, header_mode, header_color and header_filter.

Custom CSS

page.css is separate from content:

{
  "classes": [{ "selector": ".hero-title", "value": "letter-spacing: 2px;" }],
  "raw": ".my-banner { border-radius: 24px; }"
}

The builder converts it to CSS text and injects it into a <style id="page-custom-style"> element inside the page container.

.landing export files

The editor's Export action downloads <page title>.landing, a JSON file you can import into another shop:

{
  "content": { "sections": [], "style": {} },
  "title": "Spring sale",
  "description": "...",
  "image": "...",
  "direction": "ltr",
  "note": null,
  "service": "https://selldone.com"
}

On import, the builder migrates the content, keeps only sections that have an object, copies title, description, image, direction and note to the current page, and saves a history entry. An empty sections array is rejected with Sections in the file is empty!.

Migration from v1

Older pages stored each section as { name, data }. When such a section is loaded, the builder renames it to the current section name, converts data to an element tree, and continues as normal. Save the page once to store the new format. If a section cannot be migrated, the console shows The object is not defined! Please check migration from V1 to V2!.

Next steps