Skip to content

JSON Component Extension

Build custom UI components using a simple JSON design language. Create rich, data-driven content blocks without writing HTML or Thymeleaf templates—with optional AI assistance to generate components from natural language descriptions.

Overview

The JSON Component extension enables business users and developers to create custom UI components using a declarative JSON schema. Components are:

  • Theme-agnostic: Semantic tokens map to theme-specific CSS automatically
  • Data-driven: Bind content to user, order, and site context data
  • AI-assisted: Generate components from natural language prompts using Claude

Why JSON Components?

For Business Users - Create custom content blocks without developer help - Use familiar concepts (headings, text, images, buttons) - AI assistant helps generate component JSON from descriptions - Preview changes before publishing

For Developers - Consistent, validated component structure - Theme-aware styling with semantic tokens - Data binding with JSON Pointer syntax - Extensible component catalog

Quick Start

Adding a JSON Component

  1. Navigate to any page in the admin panel
  2. Click Add Extension
  3. Select JSON Component
  4. Use the JSON editor or AI assistant to create your component
  5. Save and preview

Basic Example

{
  "version": "1.0",
  "component": {
    "type": "container",
    "props": {
      "style": { "padding": "lg", "background": "surface" }
    },
    "children": [
      {
        "type": "heading",
        "props": {
          "level": 2,
          "text": "Welcome to Our Store",
          "style": { "variant": "heading-lg", "color": "primary" }
        }
      },
      {
        "type": "text",
        "props": {
          "text": "Discover our latest products and exclusive offers.",
          "style": { "variant": "body-md", "color": "muted" }
        }
      },
      {
        "type": "button",
        "props": {
          "text": "Shop Now",
          "action": { "type": "navigate", "href": "/collections/new-arrivals" },
          "style": { "variant": "button-primary" }
        }
      }
    ]
  }
}

Layout Modes

Control how the component fills the page by adding a layout property at the top level:

Mode Description Use Case
fluid Full-width, edge-to-edge (default) Hero sections, full-width backgrounds
contained Constrained to page container width Standard content sections

Full-Width (Fluid) Layout

For hero sections and full-bleed backgrounds:

{
  "version": "1.0",
  "layout": "fluid",
  "component": {
    "type": "container",
    "props": {
      "style": {
        "backgroundImage": "media/hero.jpg",
        "backgroundOverlay": "dark",
        "padding": "xl"
      }
    },
    "children": [...]
  }
}

Contained Layout

For standard content that should respect page margins:

{
  "version": "1.0",
  "layout": "contained",
  "component": {
    "type": "container",
    "props": {
      "style": { "padding": "lg" }
    },
    "children": [...]
  }
}

Full-Width with Constrained Content

For full-width backgrounds with readable text:

{
  "version": "1.0",
  "layout": "fluid",
  "component": {
    "type": "container",
    "props": {
      "style": { "backgroundImage": "media/hero.jpg", "padding": "xl" }
    },
    "children": [
      {
        "type": "container",
        "props": {
          "style": { "maxWidth": "prose" }
        },
        "children": [...]
      }
    ]
  }
}

Component Catalog

Layout Components

Container

A wrapper for grouping components with spacing, background options, and optional background images for hero sections.

{
  "type": "container",
  "props": {
    "style": { "spacing": "md", "padding": "lg", "background": "surface" }
  },
  "children": [...]
}

Style tokens: spacing, padding, background, radius, shadow, maxWidth

Background Images:

Create hero sections with image backgrounds and text overlays:

{
  "type": "container",
  "props": {
    "style": {
      "backgroundImage": "media/hero.jpg",
      "backgroundOverlay": "dark",
      "backgroundPosition": "center",
      "backgroundSize": "cover",
      "padding": "xl"
    }
  },
  "children": [
    {
      "type": "heading",
      "props": {
        "text": "Welcome",
        "style": { "color": "white" }
      }
    }
  ]
}
Token Values Description
backgroundImage URL string Image URL or media library path
backgroundOverlay none, light, medium, dark, heavy Semi-transparent overlay for text readability
backgroundPosition center, top, bottom, left, right Image positioning
backgroundSize cover, contain, auto Image sizing behavior

Row

A horizontal flex container for side-by-side layouts with responsive stacking control.

{
  "type": "row",
  "props": {
    "stackOnMobile": true,
    "style": { "gap": "md", "align": "center", "justify": "between" }
  },
  "children": [...]
}

Props: - stackOnMobile: Whether columns stack vertically on mobile (default: true)

Style tokens: gap, align, justify

Responsive Behavior: - By default (stackOnMobile: true), row children stack vertically on screens < 768px - Set stackOnMobile: false to keep columns side-by-side on all screen sizes

Column

A vertical flex container for stacking components with optional width control.

{
  "type": "column",
  "props": {
    "width": "2/3",
    "mobileWidth": "full",
    "style": { "gap": "sm", "align": "start" }
  },
  "children": [...]
}

Props: - width: Column width - 1/4, 1/3, 1/2, 2/3, 3/4, full, auto (default: auto) - mobileWidth: Width on mobile screens - 1/2, full, auto (default: full)

Style tokens: gap, align, maxWidth

Example - Asymmetric Two-Column Layout:

{
  "type": "row",
  "props": { "style": { "gap": "lg" } },
  "children": [
    {
      "type": "column",
      "props": { "width": "2/3" },
      "children": [...]
    },
    {
      "type": "column",
      "props": { "width": "1/3" },
      "children": [...]
    }
  ]
}
Width Description
1/4 25% width
1/3 33.3% width
1/2 50% width
2/3 66.6% width
3/4 75% width
full 100% width
auto Flexible width (default)

Content Components

Heading

A text heading (h1-h6) for titles and section headers.

{
  "type": "heading",
  "props": {
    "level": 2,
    "text": "Section Title",
    "style": { "variant": "heading-lg", "color": "primary" }
  }
}

Props: - level (1-6): Heading level, default 2 - text: The heading text (supports data binding) - style: Styling tokens

Style tokens: variant, color, align, transform, tracking

Text

A paragraph or inline text element.

{
  "type": "text",
  "props": {
    "text": "Your paragraph content here.",
    "style": { "variant": "body-md", "color": "muted", "align": "center" }
  }
}

Props: - text: The text content (supports data binding) - style: Styling tokens

Style tokens: variant, color, align, transform, tracking

Text Transform & Letter Spacing:

Create label-style text with uppercase and letter-spacing:

{
  "type": "text",
  "props": {
    "text": "About this demo",
    "style": {
      "transform": "uppercase",
      "tracking": "wide",
      "variant": "body-sm",
      "color": "muted"
    }
  }
}
Token Values Description
transform uppercase, lowercase, capitalize, none Text transformation
tracking tight, normal, wide, wider, widest Letter spacing

Image

An image element with optional styling.

{
  "type": "image",
  "props": {
    "src": "/images/hero.jpg",
    "alt": "Hero banner image",
    "style": { "radius": "md", "shadow": "lg" }
  }
}

Props: - src: Image URL (supports data binding) - alt: Alt text for accessibility (supports data binding) - style: Styling tokens

Divider

A horizontal line separator for visual breaks between content sections.

{
  "type": "divider",
  "props": {
    "thickness": "thin",
    "lineStyle": "dashed",
    "style": { "color": "muted" }
  }
}

Props: - thickness: Line thickness - thin, md, thick (default: md) - lineStyle: Line style - solid, dashed, dotted (default: solid) - style: Styling tokens

Style tokens: color, spacing

Blockquote

A styled quote block with optional author attribution, ideal for testimonials.

{
  "type": "blockquote",
  "props": {
    "quote": "This platform transformed our business.",
    "author": "Jane Smith",
    "role": "CEO, Acme Corp",
    "avatar": "media/avatars/jane.jpg"
  }
}

Props: - quote: The quote text (required, supports data binding) - author: Author name (supports data binding) - role: Author title/role (supports data binding) - avatar: Author avatar image URL (supports data binding) - style: Styling tokens

Style tokens: variant, color, background

Icon

A Lucide icon component with customizable size and color.

{
  "type": "icon",
  "props": {
    "name": "shopping-cart",
    "size": "lg",
    "style": { "color": "primary" }
  }
}

Props: - name: Icon name from the curated Lucide set (required) - size: Icon size - xs, sm, md, lg, xl (default: md) - style: Styling tokens

Style tokens: color

Available Icons:

Category Icons
Navigation arrow-right, arrow-left, arrow-up, arrow-down, chevron-right, chevron-left, chevron-up, chevron-down, menu, x
Actions check, plus, minus, search, settings, edit, trash, copy, download, upload, external-link
E-commerce shopping-cart, shopping-bag, credit-card, tag, gift, percent, truck, package
Communication mail, phone, message-circle
Social share, heart, star, thumbs-up
Status info, alert-circle, check-circle, x-circle, help-circle
User user, users, log-in, log-out
Misc home, calendar, clock, map-pin, eye, lock, shield, award, zap, sparkles, rocket

Icon Size Reference:

Size Pixels
xs 12px
sm 16px
md 24px
lg 32px
xl 48px

Interactive Components

A simple image carousel with auto-advance.

{
  "type": "carousel",
  "props": {
    "images": [
      { "src": "media/slide1.jpg", "alt": "Slide 1", "caption": "Welcome to our store" },
      { "src": "media/slide2.jpg", "alt": "Slide 2", "caption": "Summer collection" }
    ],
    "autoPlay": true,
    "interval": 5000,
    "showIndicators": true,
    "showControls": true,
    "style": { "radius": "lg" }
  }
}

Props: - images: Array of image objects with src, alt, and optional caption - autoPlay: Enable automatic sliding (default: true) - interval: Time between slides in milliseconds (default: 5000) - showIndicators: Show slide indicators (default: true) - showControls: Show prev/next buttons (default: true) - style: Styling tokens

Tabs

A tabbed content container for organizing content into panels.

{
  "type": "tabs",
  "children": [
    {
      "type": "tab",
      "props": { "label": "Description", "active": true },
      "children": [
        { "type": "text", "props": { "text": "Product description here." } }
      ]
    },
    {
      "type": "tab",
      "props": { "label": "Reviews" },
      "children": [
        { "type": "text", "props": { "text": "Customer reviews here." } }
      ]
    }
  ]
}

Tabs Props: - style: Styling tokens - children: Must contain tab components

Tab Props: - label: Tab label text (supports data binding) - active: Whether this tab is active by default (default: false) - children: Content to display when tab is active

Accordion

A collapsible content container for expandable sections.

{
  "type": "accordion",
  "props": { "allowMultiple": false },
  "children": [
    {
      "type": "accordionItem",
      "props": { "title": "Shipping Information", "expanded": true },
      "children": [
        { "type": "text", "props": { "text": "We ship worldwide..." } }
      ]
    },
    {
      "type": "accordionItem",
      "props": { "title": "Return Policy" },
      "children": [
        { "type": "text", "props": { "text": "30-day returns..." } }
      ]
    }
  ]
}

Accordion Props: - allowMultiple: Allow multiple sections open at once (default: false) - style: Styling tokens - children: Must contain accordionItem components

AccordionItem Props: - title: Section title (supports data binding) - expanded: Whether expanded by default (default: false) - children: Content to display when expanded

A navigation link to another page or URL.

{
  "type": "link",
  "props": {
    "text": "View All Products",
    "href": "/collections/all",
    "style": { "variant": "link" }
  }
}

Props: - text: Link text (supports data binding) - href: Target URL (supports data binding) - action: Alternative navigation action - style: Styling tokens

Button

A clickable button for navigation actions with optional icon.

{
  "type": "button",
  "props": {
    "text": "Add to Cart",
    "icon": "shopping-cart",
    "iconPosition": "left",
    "action": { "type": "navigate", "href": "/cart" },
    "style": { "variant": "button-primary" }
  }
}

Props: - text: Button text (supports data binding) - icon: Optional icon name (uses same icons as the icon component) - iconPosition: left or right (default: right) - action: Navigation action with type and href - style: Styling tokens

Available button icons: arrow-right, arrow-left, chevron-right, chevron-left, shopping-cart, shopping-bag, heart, star, check, plus, minus, search, download, upload, external-link, mail, phone, user, log-in, log-out

Example - Button with icon:

{
  "type": "button",
  "props": {
    "text": "Shop Now",
    "icon": "arrow-right",
    "iconPosition": "right",
    "action": { "type": "navigate", "href": "/collections" },
    "style": { "variant": "button-primary" }
  }
}

Spacer

An empty space element for adding gaps between components.

{
  "type": "spacer",
  "props": {
    "size": "lg"
  }
}

Props: - size: One of xs, sm, md, lg, xl

Data Binding

Bind component content to dynamic data using the $ref syntax with JSON Pointer paths.

Syntax

{
  "text": {
    "$ref": "/user/personalDetails/firstName",
    "fallback": "Guest",
    "format": "capitalize"
  }
}

Properties: - $ref: JSON Pointer path to the data - fallback: Value to use if data is not available - format: Optional transformation (capitalize, uppercase, lowercase)

Available Data Contexts

Path Description Example
/user/personalDetails/firstName User's first name "John"
/user/personalDetails/lastName User's last name "Smith"
/user/personalDetails/emailAddress User's email "[email protected]"
/order/orderReference Current order reference "ORD-12345"
/order/totalPrice Order total "99.99"
/siteContext/siteName Site name "My Store"
/item/name Current item name "Product Name"

Example: Personalized Welcome

{
  "type": "heading",
  "props": {
    "level": 1,
    "text": {
      "$ref": "/user/personalDetails/firstName",
      "fallback": "Welcome",
      "format": "capitalize"
    }
  }
}

Semantic Tokens

Style components using semantic tokens that automatically map to your theme's design system.

Typography Variants

Token Description
heading-xl Extra large heading
heading-lg Large heading
heading-md Medium heading
heading-sm Small heading
body-lg Large body text
body-md Medium body text
body-sm Small body text
button-primary Primary button style
button-secondary Secondary button style
link Link text style

Colors

Base Colors

Token Description
primary Primary brand color
secondary Secondary color
muted Muted/subtle text
success Success state
error Error state
warning Warning state

Light/Dark Variants

Token Description
primary-light Lighter shade of primary
primary-dark Darker shade of primary
secondary-light Lighter shade of secondary
secondary-dark Darker shade of secondary
success-light Lighter shade of success
success-dark Darker shade of success
error-light Lighter shade of error
error-dark Darker shade of error
warning-light Lighter shade of warning
warning-dark Darker shade of warning

Gray Scale

Token Description
gray-light Light gray
gray Medium gray
gray-dark Dark gray
white White
black Black

Spacing

Token Description
none No spacing
xs Extra small (4px)
sm Small (8px)
md Medium (16px)
lg Large (24px)
xl Extra large (32px)

Layout

Category Tokens
padding none, xs, sm, md, lg, xl
gap none, xs, sm, md, lg, xl
align left, center, right, start, end
justify start, center, end, between, around
radius none, sm, md, lg, full
shadow none, sm, md, lg

Max Width

Constrain content width for optimal readability:

Token Description
prose Optimal reading width (~65 characters)
sm Small max-width (640px)
md Medium max-width (768px)
lg Large max-width (1024px)
xl Extra large max-width (1280px)
full 100% max-width
none No max-width constraint

Example - Readable text container:

{
  "type": "container",
  "props": {
    "style": { "maxWidth": "prose", "padding": "lg" }
  },
  "children": [...]
}

Typography Transforms

Category Tokens Description
transform uppercase, lowercase, capitalize, none Text case transformation
tracking tight, normal, wide, wider, widest Letter spacing

Background Images

Category Tokens Description
backgroundImage URL string Image URL or media library path
backgroundOverlay none, light, medium, dark, heavy Semi-transparent overlay opacity
backgroundPosition center, top, bottom, left, right Image positioning
backgroundSize cover, contain, auto Image sizing behavior

Backgrounds

Token Description
surface Light gray surface
surface-light Very light surface
surface-dark Slightly darker surface
primary Primary brand color
primary-light Light primary tint
primary-dark Dark primary shade
success Success background
success-light Light success tint (for alerts)
error Error background
error-light Light error tint (for alerts)
warning Warning background
warning-light Light warning tint (for alerts)
gray-light Very light gray
gray Light gray
gray-dark Medium gray
transparent No background
white Pure white
dark Near-black section
gradient-dark The Design Brief's brand gradient, darkened where needed for light text (a primary-tinted dark wash when the brief has no gradient)
mesh-dark Dark section, tinted with the brand primary, with soft brand-colour glows

Dark sections (Nova and the themes layered on it). dark, gradient-dark, mesh-dark, primary and primary-dark are dark scopes, as are the dark hero presets (centered, gradient, video-bg). Inside one, headings read white, body text light gray, overline variants and the hero accent rule use --color-on-dark-accent, and primary buttons switch to --color-on-dark-accent with dark text, so a navy button never disappears into a navy section. Secondary and outline buttons become white outline buttons. You don't need "color": "white" on headings in these sections.

How it works: the heading variants colour through var(--color-text-strong) rather than a fixed gray, and the dark scopes re-point that token (.nova-on-dark and the nova-bg-*-dark classes in bdgr.css). --color-on-dark-accent is compiled from the Design Brief: the first of secondary, accent and primary that is light enough to read on dark, or a lightened primary. Without a brief it is the theme's --color-primary-light.

AI Assistant

Generate JSON components from natural language descriptions using Claude AI.

Using with API Key

If your site has a Claude API key configured:

  1. Type your component description in the AI prompt field
  2. Click Generate
  3. Review and edit the generated JSON
  4. Save when satisfied

Example prompts: - "Create a hero section with a welcome heading, description text, and a shop now button" - "Build a two-column layout with an image on the left and text on the right" - "Make a personalized greeting that shows the user's first name"

Using without API Key (Copy/Paste Workflow)

If you don't have an API key configured:

  1. Type your component description
  2. Click Copy Prompt to copy the full system prompt and your request
  3. Paste into claude.ai or the Claude app
  4. Copy the JSON response
  5. Click Paste Response and paste the JSON
  6. The editor will validate and apply the component

Configuring the API Key

Site administrators can configure the Claude API key:

  1. Go to Admin → Site Configuration
  2. Find Claude API Key in the AI settings section
  3. Enter your Anthropic API key
  4. Save changes

Examples

Hero Section

{
  "version": "1.0",
  "component": {
    "type": "container",
    "props": {
      "style": { "padding": "xl", "background": "surface" }
    },
    "children": [
      {
        "type": "column",
        "props": {
          "style": { "gap": "md", "align": "center" }
        },
        "children": [
          {
            "type": "heading",
            "props": {
              "level": 1,
              "text": "Summer Collection",
              "style": { "variant": "heading-xl", "align": "center" }
            }
          },
          {
            "type": "text",
            "props": {
              "text": "Discover our latest arrivals for the season",
              "style": { "variant": "body-lg", "color": "muted", "align": "center" }
            }
          },
          {
            "type": "button",
            "props": {
              "text": "Shop Now",
              "action": { "type": "navigate", "href": "/collections/summer" },
              "style": { "variant": "button-primary" }
            }
          }
        ]
      }
    ]
  }
}

Hero with Background Image

Full-width hero using "layout": "fluid" for edge-to-edge coverage:

{
  "version": "1.0",
  "layout": "fluid",
  "component": {
    "type": "container",
    "props": {
      "style": {
        "backgroundImage": "media/hero-banner.jpg",
        "backgroundOverlay": "dark",
        "backgroundPosition": "center",
        "backgroundSize": "cover",
        "padding": "xl"
      }
    },
    "children": [
      {
        "type": "column",
        "props": {
          "style": { "gap": "md", "align": "center" }
        },
        "children": [
          {
            "type": "text",
            "props": {
              "text": "NEW ARRIVAL",
              "style": {
                "transform": "uppercase",
                "tracking": "widest",
                "variant": "body-sm",
                "color": "white"
              }
            }
          },
          {
            "type": "heading",
            "props": {
              "level": 1,
              "text": "Winter Collection 2025",
              "style": { "variant": "heading-xl", "color": "white", "align": "center" }
            }
          },
          {
            "type": "button",
            "props": {
              "text": "Explore Now",
              "action": { "type": "navigate", "href": "/collections/winter" },
              "style": { "variant": "button-primary" }
            }
          }
        ]
      }
    ]
  }
}

Two-Column Feature

{
  "version": "1.0",
  "component": {
    "type": "row",
    "props": {
      "style": { "gap": "xl", "align": "center" }
    },
    "children": [
      {
        "type": "image",
        "props": {
          "src": "/images/feature.jpg",
          "alt": "Feature image",
          "style": { "radius": "lg", "shadow": "md" }
        }
      },
      {
        "type": "column",
        "props": {
          "style": { "gap": "md" }
        },
        "children": [
          {
            "type": "heading",
            "props": {
              "level": 2,
              "text": "Quality Craftsmanship",
              "style": { "variant": "heading-lg" }
            }
          },
          {
            "type": "text",
            "props": {
              "text": "Each product is carefully crafted with attention to detail and premium materials.",
              "style": { "variant": "body-md", "color": "secondary" }
            }
          },
          {
            "type": "link",
            "props": {
              "text": "Learn more about our process",
              "href": "/about/craftsmanship",
              "style": { "variant": "link" }
            }
          }
        ]
      }
    ]
  }
}

Personalized Welcome Banner

{
  "version": "1.0",
  "component": {
    "type": "container",
    "props": {
      "style": { "padding": "md", "background": "primary" }
    },
    "children": [
      {
        "type": "row",
        "props": {
          "style": { "justify": "between", "align": "center" }
        },
        "children": [
          {
            "type": "text",
            "props": {
              "text": {
                "$ref": "/user/personalDetails/firstName",
                "fallback": "Welcome back!",
                "format": "capitalize"
              },
              "style": { "variant": "body-md" }
            }
          },
          {
            "type": "link",
            "props": {
              "text": "View your orders",
              "href": "/account/orders",
              "style": { "variant": "link" }
            }
          }
        ]
      }
    ]
  }
}

Testimonial with Blockquote

{
  "version": "1.0",
  "component": {
    "type": "container",
    "props": {
      "style": { "padding": "lg", "background": "surface" }
    },
    "children": [
      {
        "type": "blockquote",
        "props": {
          "quote": "The quality of these products exceeded all my expectations. Will definitely be ordering again!",
          "author": "Sarah Johnson",
          "role": "Verified Customer",
          "avatar": "media/avatars/sarah.jpg"
        }
      }
    ]
  }
}

Feature Card with Icon

{
  "version": "1.0",
  "component": {
    "type": "container",
    "props": {
      "style": { "padding": "lg", "background": "surface", "radius": "lg" }
    },
    "children": [
      {
        "type": "column",
        "props": {
          "style": { "gap": "md", "align": "center" }
        },
        "children": [
          {
            "type": "icon",
            "props": {
              "name": "truck",
              "size": "xl",
              "style": { "color": "primary" }
            }
          },
          {
            "type": "heading",
            "props": {
              "level": 3,
              "text": "Free Shipping",
              "style": { "variant": "heading-md", "align": "center" }
            }
          },
          {
            "type": "text",
            "props": {
              "text": "On all orders over $50. Fast, reliable delivery to your door.",
              "style": { "variant": "body-sm", "color": "muted", "align": "center" }
            }
          }
        ]
      }
    ]
  }
}

Feature Grid with Icons

{
  "version": "1.0",
  "component": {
    "type": "row",
    "props": {
      "style": { "gap": "lg" }
    },
    "children": [
      {
        "type": "column",
        "props": { "width": "1/3" },
        "children": [
          {
            "type": "column",
            "props": { "style": { "gap": "sm", "align": "center" } },
            "children": [
              { "type": "icon", "props": { "name": "shield", "size": "lg", "style": { "color": "success" } } },
              { "type": "heading", "props": { "level": 4, "text": "Secure Payment", "style": { "variant": "heading-sm" } } },
              { "type": "text", "props": { "text": "256-bit SSL encryption", "style": { "variant": "body-sm", "color": "muted" } } }
            ]
          }
        ]
      },
      {
        "type": "column",
        "props": { "width": "1/3" },
        "children": [
          {
            "type": "column",
            "props": { "style": { "gap": "sm", "align": "center" } },
            "children": [
              { "type": "icon", "props": { "name": "package", "size": "lg", "style": { "color": "primary" } } },
              { "type": "heading", "props": { "level": 4, "text": "Easy Returns", "style": { "variant": "heading-sm" } } },
              { "type": "text", "props": { "text": "30-day return policy", "style": { "variant": "body-sm", "color": "muted" } } }
            ]
          }
        ]
      },
      {
        "type": "column",
        "props": { "width": "1/3" },
        "children": [
          {
            "type": "column",
            "props": { "style": { "gap": "sm", "align": "center" } },
            "children": [
              { "type": "icon", "props": { "name": "phone", "size": "lg", "style": { "color": "secondary" } } },
              { "type": "heading", "props": { "level": 4, "text": "24/7 Support", "style": { "variant": "heading-sm" } } },
              { "type": "text", "props": { "text": "Always here to help", "style": { "variant": "body-sm", "color": "muted" } } }
            ]
          }
        ]
      }
    ]
  }
}

Theme Support

JSON Components automatically adapt to your site's theme:

Theme Behavior
Nova Uses CSS custom properties (--font-size-xl, --color-primary, etc.)
Bootstrap Uses Bootstrap utility classes (display-4, text-primary, p-4, etc.)
Other themes Falls back to Bootstrap classes

The semantic token system ensures your components look correct regardless of which theme is active.

Best Practices

Structure

  • Use container as the root for consistent padding
  • Nest row and column for complex layouts
  • Keep component hierarchies shallow (3-4 levels max)

Data Binding

  • Always provide a fallback for data bindings
  • Use format to ensure consistent text presentation
  • Test with logged-out users to verify fallbacks work

Styling

  • Prefer semantic tokens over custom CSS
  • Use consistent spacing tokens throughout
  • Test on both desktop and mobile viewports

Performance

  • Avoid deeply nested component trees
  • Use images with appropriate sizes
  • Keep JSON payloads under 50KB

Troubleshooting

Component Not Rendering

Check: - JSON is valid (use the editor's validation) - Component types are spelled correctly - Required props (text, src) are provided

Data Binding Not Working

Check: - Path starts with / (e.g., /user/personalDetails/firstName) - User is logged in (for user data) - Fallback is provided for testing

Styling Looks Wrong

Check: - Token names are correct (e.g., heading-lg not large-heading) - Theme is properly configured - Browser developer tools for CSS conflicts

Support

  • Documentation: This guide
  • Example Components: See the examples above
  • Developer Reference: Check commerce-core/.../extensions/jsoncomponent/ for implementation details
  • Component Catalog: View ComponentCatalog.java for all available components and props