Build dynamic, data-driven layouts with RSL's powerful JSON engine
The JSON API provides 50+ semantic content types—no need to write raw HTML:
| Breakpoint | Min Width | Typical Use |
|---|---|---|
xs | 0px (default) | Mobile phones |
sm | 480px | Large phones |
md | 768px | Tablets |
lg | 1024px | Laptops |
xl | 1280px | Desktops |
xxl | 1600px | Large screens |
const myLayout = {
version: 2,
layoutId: "my-first-layout",
breakpoints: {
xs: 1, // 1 column on mobile
md: 3 // 3 columns on desktop
},
gap: "1.5rem",
items: [
{
content: {
type: "card",
title: "Getting Started",
body: "Learn the basics of RSL",
button: { text: "Learn More", variant: "primary" }
}
},
{
content: {
type: "card",
title: "Components",
body: "Explore 30+ UI components",
button: { text: "Browse", variant: "outline" }
}
},
{
content: {
type: "card",
title: "Templates",
body: "Production-ready templates",
button: { text: "View All", variant: "outline" }
}
}
]
};
You now have a responsive 3-column card grid. No HTML written—just JSON configuration with semantic content types like card, button, heading, accordion, gallery, and more.
Use semantic types for common patterns, or type: "html" for custom content:
card, grid, balanced, divider, spacer
heading, paragraph, text, list, badge
button, link, accordion, tabs, modal, tooltip, popover
image, thumbnail, gallery, carousel, video-player, icon, iframe
table, smart-table, chart, kpi, gantt, progress, calendar
select, datepicker, timepicker, filter, star-rating, form
navbar, breadcrumb, pagination, sidebar, offcanvas
alert, inlayAlert, toast, skeleton, announcements
hero, testimonial, pricing-table, iconpicker
html, slot, component — for anything else
See full schema with all properties for each type
For custom designs not covered by semantic types, use type: "html":
items: [
// Semantic: Built-in card component
{ content: { type: "card", title: "Standard Card", body: "Uses built-in styling" } },
// Custom: Your own HTML for unique designs
{
content: {
type: "html",
value: `
`
}
},
// Semantic: Built-in accordion component
{ content: { type: "accordion", items: [...] } }
]
Renders a layout from JSON configuration into a DOM container.
HTMLElement - The created layout element
const layout = RSL.JSONLayout.renderLayout('#app', {
version: 2,
layoutId: "dashboard",
breakpoints: { xs: 1, md: 2, lg: 4 },
items: [
{ content: { type: "card", title: "Widget 1", body: "..." } },
{ content: { type: "card", title: "Widget 2", body: "..." } }
]
});
Extracts JSON configuration from an existing HTML layout.
Object - JSON layout configuration
// Extract JSON from existing layout
const config = RSL.JSONLayout.buildFromDOM('#my-layout');
// Save to database
await fetch('/api/save-layout', {
method: 'POST',
body: JSON.stringify(config)
});
buildFromDOM(container) — Extracts JSON from an existing .slot-layout element inside a container. Best for extracting layouts you've already rendered.
convertHTMLtoJSON(source) — Converts any HTML string, element, or full document to JSON. More flexible—works with HTML strings, can parse full pages, and finds multiple layouts. Best for importing HTML from external sources or converting entire pages.
The StateManager module provides undo/redo history, named presets, and import/export functionality. It's optional—use it when you need users to save, share, or restore layout configurations. Included in the same layout-json-engine-v2.js file.
Saves current layout state as a named preset.
RSL.StateManager.savePreset('My Dashboard', 'Custom layout for analytics');
Loads a previously saved preset by name.
boolean - Success status
RSL.StateManager.loadPreset('My Dashboard');
Exports current layout state (and optionally schema) as JSON.
// Export full layout (schema + state)
const fullExport = RSL.StateManager.toJSON({
includeSchema: true,
container: '#app'
});
// Save to file or send to server
const json = JSON.stringify(fullExport, null, 2);
localStorage.setItem('my-layout', json);
Validate your JSON configuration before rendering to catch errors early:
Validates a JSON layout configuration and returns errors/warnings.
{ valid: boolean, errors: string[], warnings: string[] }
const config = {
version: 2,
layoutId: "my-layout",
breakpoints: { xs: 1, md: 3 },
items: [{ content: { type: "card", title: "Test" } }]
};
// Validate before rendering
const result = RSL.JSONLayout.validateSchema(config);
if (!result.valid) {
console.error('Layout errors:', result.errors);
// Handle errors - show user message, etc.
} else {
// Safe to render
RSL.JSONLayout.renderLayout('#container', config);
}
// Warnings don't prevent rendering but indicate potential issues
if (result.warnings.length > 0) {
console.warn('Layout warnings:', result.warnings);
}
// Backend API endpoint (Node.js + Express)
app.get('/api/page/:pageId', async (req, res) => {
const page = await db.query(
'SELECT layout_json FROM pages WHERE id = ?',
[req.params.pageId]
);
res.json(page.layout_json);
});
// Frontend
async function loadPage(pageId) {
const layout = await fetch(`/api/page/${pageId}`).then(r => r.json());
RSL.JSONLayout.renderLayout('#content', layout);
}
// Let users save custom dashboard layouts
function saveDashboard() {
const layoutName = prompt('Name your dashboard layout:');
if (layoutName) {
RSL.StateManager.savePreset(layoutName);
alert('Dashboard saved!');
}
}
// On page load, restore user's last used dashboard
const savedPresets = RSL.StateManager.getPresetNames();
if (savedPresets.length > 0) {
// Load first preset
RSL.StateManager.loadPreset(savedPresets[0]);
}
// Show different layout variants to different users
const variants = {
A: { /* layout with hero banner */ },
B: { /* layout with video hero */ },
C: { /* layout with carousel */ }
};
// Randomly assign variant
const variant = ['A', 'B', 'C'][Math.floor(Math.random() * 3)];
// Track which variant user sees
analytics.track('layout_variant_shown', { variant });
// Render the variant
RSL.JSONLayout.renderLayout('#hero', variants[variant]);
// Fetch products from API
const products = await fetch('/api/products').then(r => r.json());
// Create layout dynamically with semantic card type
const productLayout = {
version: 2,
layoutId: "products-grid",
breakpoints: { xs: 1, sm: 2, lg: 4 },
gap: "2rem",
items: products.map(product => ({
content: {
type: "card",
image: product.image,
title: product.name,
price: `$${product.price}`,
button: { text: "Add to Cart", variant: "primary" }
}
}))
};
RSL.JSONLayout.renderLayout('#products', productLayout);
// Admin creates a layout template
const template = RSL.JSONLayout.buildFromDOM('#template-preview');
// Deploy to multiple client sites
const sites = ['site1.com', 'site2.com', 'site3.com'];
for (const site of sites) {
await fetch(`https://${site}/api/update-layout`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
section: 'homepage-hero',
layout: template
})
});
}
console.log('Layout deployed to all sites!');
Let users customize which metrics they see, resize widgets, and save multiple dashboard layouts for different purposes.
// User customizes their analytics dashboard
RSL.StateManager.savePreset('Sales Dashboard');
RSL.StateManager.savePreset('Traffic Dashboard');
RSL.StateManager.savePreset('Conversion Dashboard');
Store managers can rearrange featured products, test different layouts, and schedule layout changes for promotions.
// Fetch products and render in customizable grid
const products = await getProducts();
const layout = generateProductGrid(products);
RSL.JSONLayout.renderLayout('#products', layout);
Editors can control homepage layout without developer intervention. A/B test article placement to optimize engagement.
// CMS stores layout for each page section
const heroLayout = await cms.getLayout('homepage-hero');
const articlesLayout = await cms.getLayout('homepage-articles');
RSL.JSONLayout.renderLayout('#hero', heroLayout);
RSL.JSONLayout.renderLayout('#articles', articlesLayout);
Build drag-and-drop editors where users design pages visually, then export/publish as JSON.
// After user edits layout visually
const finalLayout = RSL.JSONLayout.buildFromDOM('#editor');
// Publish to production
await publishPage(finalLayout);
Each tenant/customer can have their own custom layout while sharing the same codebase.
// Load tenant-specific layout
const tenantId = getCurrentTenant();
const layout = await fetch(`/api/tenant/${tenantId}/layout`).then(r => r.json());
RSL.JSONLayout.renderLayout('#app', layout);
Instructors arrange course modules and content. Students can customize their learning dashboard.
// Student customizes their course dashboard
const studentLayout = RSL.StateManager.toJSON({ includeSchema: true });
await saveStudentPreferences(studentId, studentLayout);
All these use cases follow the same pattern:
renderLayout()