Skip to main content

Data Binding System

The QwickApps React Framework data binding system enables AI-driven component configuration through CMS data rather than hardcoded props. This is the foundation for building dynamic, content-driven applications where components automatically resolve their content from data sources.

Overview

Instead of hardcoding component props, the data binding system allows components to fetch their content dynamically from configured data sources. This enables:

  • Clear separation between content and presentation
  • Runtime validation of content data with schemas
  • Flexible fallback mechanisms for missing or invalid data
  • Type-safe component configuration with TypeScript support
  • CMS integration patterns for headless content management

Quick Start

Traditional vs Data-Driven Approach

Traditional Approach (Hardcoded Props):

<SafeSpan
html="<p>This content is <strong>hardcoded</strong> in the component props.</p>"
placeholder="Hardcoded placeholder"
/>

Data-Driven Approach (CMS Data):

<SafeSpan dataSource="company.description" />

Basic Setup

  1. Configure Data Provider with your CMS data:
import { JsonDataProvider } from '@qwickapps/schema';
import { DataProvider } from '@qwickapps/react-framework';

const cmsData = {
'company.description': [
{
html: '<p>QwickApps React Framework provides comprehensive tools with <strong>minimal effort</strong>.</p>',
placeholder: 'Loading company description...'
}
]
};

const dataProvider = new JsonDataProvider({ data: cmsData });

function App() {
return (
<DataProvider dataSource={{ dataProvider }}>
<SafeSpan dataSource="company.description" />
</DataProvider>
);
}

Data Source Structure

Data Source Keys

Data sources use dot notation to reference nested content:

const cmsData = {
// Company information
'company.tagline': [{ html: '<h1>Build Apps <em>Faster</em></h1>' }],
'company.description': [{ html: '<p>Comprehensive development tools</p>' }],

// Page-specific content
'pages.home.hero-subtitle': [{ html: '<p class="subtitle">Modern web development</p>' }],
'pages.about.mission': [{ html: '<p>Empower developers worldwide</p>' }],

// Feature descriptions
'features.responsive-design': [{ html: '<p>Built-in responsive patterns</p>' }],
'features.performance': [{ html: '<p>Optimized rendering and caching</p>' }],

// Marketing content
'marketing.cta': [{ html: '<p><strong>Get started today!</strong></p>' }],
'testimonials.developer': [{ html: '<blockquote>QwickApps has <em>revolutionized</em> our workflow</blockquote>' }]
};

Content Item Structure

Each data source contains an array of content items with:

{
html?: string; // Rich HTML content (optional)
placeholder?: string; // Loading/fallback text (optional)
}

Example:

'company.welcome': [
{
html: '<h2>Welcome to QwickApps</h2><p>Build amazing applications faster.</p>',
placeholder: 'Loading welcome message...'
}
]

Component Usage

SafeSpan Component

The primary component for displaying data-bound HTML content:

// Basic usage
<SafeSpan dataSource="company.tagline" />

// With fallback props
<SafeSpan
dataSource="company.description"
html="<p>Fallback content when CMS data is empty</p>"
placeholder="Fallback placeholder"
/>

// Custom binding options
<SafeSpan
dataSource="marketing.announcement"
bindingOptions={{
fallback: {
html: '<p>No announcements at this time</p>',
placeholder: 'Loading announcements...'
}
}}
/>

Other Data-Bound Components

Many Framework components support the dataSource prop:

// Button with data binding
<Button dataSource="buttons.primary" />

// Article with data binding
<Article dataSource="articles.featured" />

// Section with data binding
<Section dataSource="sections.hero" />

Data Providers

JsonDataProvider

For static JSON data or local development:

import { JsonDataProvider } from '@qwickapps/schema';

const jsonProvider = new JsonDataProvider({
data: cmsData
});

CachedDataProvider

For performance optimization with automatic caching:

import { CachedDataProvider, JsonDataProvider } from '@qwickapps/schema';

const jsonProvider = new JsonDataProvider({ data: cmsData });
const cachedProvider = new CachedDataProvider(jsonProvider, {
maxSize: 100, // Cache up to 100 items
defaultTTL: 60000 // 1-minute cache TTL
});

Advanced Features

Multi-Language Support

Dynamic language switching using data source paths:

function MultiLanguageContent() {
const [language, setLanguage] = useState<'en' | 'es'>('en');

return (
<div>
<Button onClick={() => setLanguage('en')}>English</Button>
<Button onClick={() => setLanguage('es')}>Español</Button>
<SafeSpan dataSource={`content.${language}.welcome`} />
</div>
);
}

Multi-language data structure:

{
'content.en.welcome': [
{ html: '<h2>Welcome to QwickApps</h2>' }
],
'content.es.welcome': [
{ html: '<h2>Bienvenidos a QwickApps</h2>' }
]
}

A/B Testing Support

Dynamic content variants for conversion optimization:

function ABTestingExample() {
const [variant, setVariant] = useState<'a' | 'b'>('a');

return (
<div>
<Button onClick={() => setVariant('a')}>Variant A</Button>
<Button onClick={() => setVariant('b')}>Variant B</Button>
<SafeSpan dataSource={`cta.variant-${variant}`} />
</div>
);
}

A/B test data structure:

{
'cta.variant-a': [
{ html: '<p><strong>Start Building Today!</strong> - Try our free plan.</p>' }
],
'cta.variant-b': [
{ html: '<p><strong>Join 10,000+ Developers</strong> - Get started now.</p>' }
]
}

Rich Media Content

Complex HTML content for blogs and articles:

<SafeSpan dataSource="blog.featured-post" />

Rich media data:

'blog.featured-post': [
{
html: `
<article>
<h3>Building Scalable Apps</h3>
<p class="meta">Published January 15, 2025 • 8 min read</p>
<p>Learn how our <strong>data-binding system</strong> enables dynamic applications...</p>
<a href="/blog/scalable-apps" class="read-more">Continue reading →</a>
</article>
`,
placeholder: 'Loading featured blog post...'
}
]

Error Handling & Fallbacks

Automatic Fallback Behavior

The system handles missing or invalid data gracefully:

// Non-existent data source - shows fallback placeholder
<SafeSpan
dataSource="does.not.exist"
placeholder="This content is coming soon..."
/>

// Empty data source - uses fallback HTML
<SafeSpan
dataSource="empty.content"
html="<p>Fallback content when CMS data is empty</p>"
/>

// Custom fallback options
<SafeSpan
dataSource="unreliable.data"
bindingOptions={{
fallback: {
html: '<p>Custom fallback for <strong>unreliable data</strong></p>',
placeholder: 'Custom fallback placeholder'
}
}}
/>

Error Handling Strategy

The system follows a predictable fallback hierarchy:

  1. CMS Content: Uses html from data source if available
  2. CMS Placeholder: Uses placeholder from data source if html is empty
  3. Fallback Props: Uses component's html prop if data source fails
  4. Fallback Placeholder: Uses component's placeholder prop as last resort
  5. Custom Fallback: Uses bindingOptions.fallback if provided

Security Features

Automatic HTML Sanitization

All HTML content is automatically sanitized to prevent XSS attacks:

// Malicious content is automatically cleaned
<SafeSpan dataSource="security.malicious" />

What gets filtered:

  • <script> tags are removed
  • onerror and other dangerous attributes are filtered
  • Only safe HTML elements are preserved
  • XSS protection is built-in

Example malicious content:

'security.malicious': [
{
html: '<script>alert("XSS")</script><p>Safe content with <strong>formatting</strong></p>',
placeholder: 'Loading content...'
}
]

Result: Only the safe paragraph with formatting is rendered.

Performance Optimization

Caching Strategy

Use CachedDataProvider for optimal performance:

const cachedProvider = new CachedDataProvider(jsonProvider, {
maxSize: 100, // Cache up to 100 items
defaultTTL: 60000 // 1-minute TTL
});

Performance features:

  • Memory caching with configurable TTL
  • Automatic content chunking for large data
  • Efficient re-rendering on data changes
  • Cache hit ratio monitoring

Large Content Handling

The system efficiently handles large content blocks:

// Large content with scrollable container
<div style={{ maxHeight: '200px', overflow: 'auto' }}>
<SafeSpan dataSource="performance.large-content" />
</div>

Custom Hook Usage

useDataBinding Hook

For advanced use cases, use the hook directly:

import { useDataBinding } from '@qwickapps/react-framework';

function CustomComponent({ dataSource }: { dataSource: string }) {
const { loading, error } = useDataBinding(
dataSource,
{
html: '<p>Fallback HTML content</p>',
placeholder: 'Fallback placeholder'
},
undefined,
{
strict: true, // Enable strict schema validation
cache: true // Enable caching for performance
}
);

if (loading) {
return <div>Loading content...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

return <SafeSpan dataSource={dataSource} />;
}

Hook Options

const options = {
strict: true, // Enable strict schema validation
cache: true, // Enable caching for performance
fallback: { // Custom fallback data
html: '<p>Custom fallback content</p>',
placeholder: 'Custom placeholder'
}
};

Schema System

Component Schemas

Components define schemas for data validation and CMS integration:

import { toDataSchema, createFieldMapping } from '../utils/toDataSchema';

const schema = toDataSchema<SafeSpanProps>({
componentName: 'SafeSpan',
description: 'Safely renders HTML content with automatic sanitization',
usageExamples: [
'<SafeSpan dataSource="company.description" />',
'<SafeSpan dataSource="pages.home.tagline" />'
]
}, {
html: createFieldMapping.richText({
required: false,
instructions: 'HTML content to display safely'
}),
placeholder: createFieldMapping.text({
required: false,
instructions: 'Text to show when no content is available'
})
});

Schema Benefits

  • Field Types: Defines whether content should be text, richText, etc.
  • Validation: Ensures content meets component requirements
  • Editor Instructions: Guides content editors with context
  • Usage Examples: Shows proper dataSource syntax
  • Type Safety: Runtime validation of CMS data

Best Practices

Do

  • Use semantic data source names (company.tagline, features.responsive)
  • Provide meaningful fallback content for better user experience
  • Use caching for frequently accessed content
  • Test with empty and invalid data sources
  • Leverage multi-language support for global applications
  • Use A/B testing for conversion optimization

Don't

  • Hardcode content when CMS integration is available
  • Forget to provide fallback content for critical sections
  • Mix data sources and hardcoded props unnecessarily
  • Ignore the automatic HTML sanitization (it's a security feature)
  • Use overly complex data source paths (keep them semantic)
  • Bypass the schema system for custom components

Integration Examples

WordPress Integration

// WordPress-style data structure
{
'posts.featured': [
{
html: '<article><h2>Latest Post</h2><p>Post content...</p></article>',
placeholder: 'Loading latest post...'
}
],
'pages.about': [
{
html: '<div>About page content from WordPress</div>',
placeholder: 'Loading about page...'
}
]
}

Headless CMS Integration

// Strapi/Contentful-style data structure
{
'content-types.hero-section': [
{
html: '<section><h1>Dynamic Hero</h1><p>From headless CMS</p></section>',
placeholder: 'Loading hero section...'
}
]
}

What's Next?