Quick reference guide for the RSL JSON Layout format
{
// REQUIRED FIELDS
version: 2, // Must be 2
layoutId: string, // Unique ID (e.g., "my-layout")
breakpoints: { // At least one breakpoint required
xs?: number, // Columns at <480px
sm?: number, // Columns at >=480px
md?: number, // Columns at >=768px
lg?: number, // Columns at >=1024px
xl?: number, // Columns at >=1280px
xxl?: number // Columns at >=1600px
},
// OPTIONAL FIELDS
gap?: string, // Gap between items (e.g., "1.5rem")
pageMode?: boolean, // Full page rendering mode
// CONTENT (choose one)
items?: LayoutItem[], // Array of layout items
template?: { // OR template system
data: any[], // Array of data objects
item: LayoutItem // Template for each item
},
// ADVANCED
gridAreas?: { // Named grid areas per breakpoint
xs?: GridAreaConfig,
sm?: GridAreaConfig,
md?: GridAreaConfig,
lg?: GridAreaConfig
}
}
{
// OPTIONAL (V2 doesn't require id)
id?: string, // Unique ID
classes?: string[], // CSS classes
order?: number, // Flex order
visible?: boolean, // Show/hide (default: true)
area?: string, // Grid area name (for gridAreas)
// RESPONSIVE SPANNING
span?: { // Column span per breakpoint
xs?: number,
sm?: number,
md?: number,
lg?: number,
xl?: number,
xxl?: number
},
// GRID POSITIONING (alternative to span)
grid?: {
rowStart?: number,
rowEnd?: number,
columnStart?: number,
columnEnd?: number
},
// CONTENT
content?: ContentConfig, // Item content (see Content Types)
// STYLING
style?: { // Inline styles
[property: string]: string
},
// DATA ATTRIBUTES
data?: {
[key: string]: string // Becomes data-{key}="{value}"
}
}
V2 supports 50+ semantic content types:
// Card
{ type: "card", title: string, body?: string, image?: string,
titleIcon?: string, subtitle?: string, price?: string,
button?: ButtonConfig, buttons?: ButtonConfig[] }
// Nested Grid
{ type: "grid", breakpoints: object, gap?: string, items: LayoutItem[] }
// Balanced (Masonry)
{ type: "balanced", breakpoints: object, gap?: string, items: LayoutItem[] }
// Divider
{ type: "divider" }
// Spacer
{ type: "spacer", height?: string }
// Heading
{ type: "heading", text: string, level?: 1|2|3|4|5|6 }
// Paragraph
{ type: "paragraph", text: string }
// Text
{ type: "text", value: string }
// List
{ type: "list", items: string[], ordered?: boolean }
// Badge
{ type: "badge", text: string, variant?: string }
// Button
{ type: "button", text: string, variant?: string, href?: string,
icon?: string, onClick?: string }
// Link
{ type: "link", text: string, href: string, target?: string }
// Accordion
{ type: "accordion", variant?: "classic"|"modern", allowMultiple?: boolean,
items: { title: string, content: string, open?: boolean }[] }
// Tabs
{ type: "tabs", variant?: "horizontal"|"vertical",
tabs: { id: string, label: string, content: string, active?: boolean }[] }
// Modal
{ type: "modal", id: string, title: string, body: string,
trigger?: { text: string, variant?: string } }
// Select
{ type: "select", options: { value: string, label: string }[],
placeholder?: string, multi?: boolean, searchable?: boolean }
// Toast
{ type: "toast", header?: string, body: string, position?: string,
variant?: string, autoClose?: number }
// Image
{ type: "image", src: string, alt: string, width?: string, height?: string }
// Thumbnail
{ type: "thumbnail", src: string, alt: string, caption?: string }
// Gallery
{ type: "gallery", images: { src: string, alt: string, caption?: string }[],
columns?: object, gap?: string, lightbox?: boolean }
// Carousel
{ type: "carousel", slides: { src: string, alt: string, caption?: string }[],
autoPlay?: boolean, interval?: number }
// Video Player
{ type: "video-player", src: string, poster?: string, controls?: boolean }
// Icon
{ type: "icon", name: string, size?: string }
// Iframe
{ type: "iframe", src: string, width?: string, height?: string, title?: string }
// Table
{ type: "table", headers: string[], rows: any[][],
striped?: boolean, hoverable?: boolean, responsive?: boolean }
// Smart Table
{ type: "smart-table", columns: ColumnConfig[], data: any[],
sortable?: boolean, filterable?: boolean, pagination?: boolean }
// Chart
{ type: "chart", chartType: "bar"|"line"|"area"|"pie"|"doughnut",
data: { label: string, value: number }[], colorScheme?: string,
showLegend?: boolean, showGrid?: boolean }
// KPI
{ type: "kpi", title: string, value: string|number,
trend?: "up"|"down"|"neutral", change?: string }
// Progress
{ type: "progress", value: number, max?: number, variant?: string }
// Calendar
{ type: "calendar", events?: EventConfig[], view?: "month"|"week"|"day" }
// Gantt
{ type: "gantt", tasks: TaskConfig[], startDate?: string, endDate?: string }
// Navbar
{ type: "navbar", brand?: { text: string, href: string },
items: { text: string, href: string, active?: boolean }[] }
// Breadcrumb
{ type: "breadcrumb", items: { text: string, href?: string }[] }
// Pagination
{ type: "pagination", currentPage: number, totalPages: number }
// Sidebar
{ type: "sidebar", position?: "left"|"right", items: NavItem[] }
// Form
{ type: "form", fields: FieldConfig[], submitText?: string }
// Date Picker
{ type: "datepicker", value?: string, min?: string, max?: string }
// Filter
{ type: "filter", filters: FilterConfig[] }
// Star Rating
{ type: "star-rating", value?: number, max?: number, readonly?: boolean }
// Alert
{ type: "alert", message: string, variant?: "success"|"danger"|"warning"|"info",
dismissible?: boolean }
// Inlay Alert
{ type: "inlayAlert", message: string, variant?: string, autoDismiss?: number }
// Skeleton
{ type: "skeleton", variant?: "text"|"avatar"|"card"|"table", rows?: number }
// Announcements
{ type: "announcements", items: { title: string, message: string }[] }
// Hero
{ type: "hero", title: string, subtitle?: string, backgroundImage?: string,
buttons?: ButtonConfig[], centered?: boolean }
// Testimonial
{ type: "testimonial", quote: string, author: string,
role?: string, avatar?: string, rating?: number }
// Pricing Table
{ type: "pricing-table", plans: PlanConfig[] }
// Raw HTML
{ type: "html", value: string }
// Plain Text
{ type: "text", value: string }
// Template Slot
{ type: "slot", selector: string }
// Component Reference
{ type: "component", component: string, props?: object }
Render arrays of data with {{variable}} interpolation:
{
version: 2,
layoutId: "products",
breakpoints: { xs: 1, md: 2, lg: 3 },
template: {
data: [
{ name: "Product 1", price: "99", image: "img1.jpg" },
{ name: "Product 2", price: "149", image: "img2.jpg" }
],
item: {
content: {
type: "card",
image: "{{image}}",
title: "{{name}}",
price: "${{price}}"
}
}
}
}
{{key}} - Replace with data[key]{{index}} - Current item index (0-based){{index1}} - Current item index (1-based)Named grid areas for complex layouts:
{
version: 2,
layoutId: "app-layout",
gridAreas: {
xs: {
areas: [["header"], ["nav"], ["main"], ["footer"]],
columns: "1fr",
rows: "auto auto 1fr auto"
},
md: {
areas: [
["header", "header"],
["nav", "main"],
["footer", "footer"]
],
columns: "200px 1fr",
rows: "auto 1fr auto"
}
},
items: [
{ area: "header", content: { type: "heading", text: "App" } },
{ area: "nav", content: { type: "html", value: "<nav>...</nav>" } },
{ area: "main", content: { type: "html", value: "<main>...</main>" } },
{ area: "footer", content: { type: "text", value: "Footer" } }
]
}
{
// REQUIRED FIELDS
version: 1, // Must be 1
layoutId: string, // Unique ID
breakpoints: { // At least one required
xs?: number, // Columns at <576px
sm?: number, // Columns at >=576px
md?: number, // Columns at >=768px
lg?: number, // Columns at >=992px
xl?: number, // Columns at >=1200px
xxl?: number // Columns at >=1400px
},
items: LayoutItem[], // Array of items (required)
// OPTIONAL FIELDS
gap?: string, // Gap between items
wrapper?: { // Parent container element
tag?: string,
id?: string,
classes?: string[],
data?: object
}
}
{
// REQUIRED
id: string, // Unique ID (required in V1)
// OPTIONAL
classes?: string[], // CSS classes
order?: number, // Flex order
visible?: boolean, // Show/hide (default: true)
grid?: { // Grid positioning
rowStart?: number,
rowEnd?: number,
columnStart?: number,
columnEnd?: number
},
content?: { // V1 content types only
type: "html" | "text" | "slot" | "component",
value?: string, // For "html" or "text"
selector?: string, // For "slot"
component?: string, // For "component"
props?: object // For "component"
},
data?: { // Data attributes
[key: string]: string
}
}
| Feature | V1 | V2 |
|---|---|---|
| Version number | 1 |
2 |
Item id |
Required | Optional |
| Content types | 4 (html, text, slot, component) | 50+ semantic types |
| Template system | No | Yes ({{variable}}) |
| Responsive spans | No | Yes (span: { xs: 1, md: 2 }) |
| Grid areas | No | Yes |
| Page mode | No | Yes |
const result = RSL.JSONLayout.validateSchema(config);
if (!result.valid) {
console.error('Errors:', result.errors);
console.warn('Warnings:', result.warnings);
}
// ❌ Missing layoutId
{ version: 2, breakpoints: { xs: 1 }, items: [] }
// Error: layoutId is required
// ❌ Invalid content type
{ content: { type: "invalid" } }
// Warning: unknown content type "invalid"
// ❌ Template without data
{ template: { item: { content: { type: "card" } } } }
// Error: template.data is required
{
version: 1,
layoutId: "cards",
breakpoints: { xs: 1, md: 3 },
items: [{
id: "card-1",
content: {
type: "html",
value: "<div class='card'><h3>Title</h3><p>Body</p></div>"
}
}]
}
{
version: 2,
layoutId: "cards",
breakpoints: { xs: 1, md: 3 },
items: [{
content: {
type: "card",
title: "Title",
body: "Body"
}
}]
}
Version: 2.0.0 | Last Updated: December 2025 | Schema Versions: 1, 2