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
- 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:
- CMS Content: Uses
htmlfrom data source if available - CMS Placeholder: Uses
placeholderfrom data source ifhtmlis empty - Fallback Props: Uses component's
htmlprop if data source fails - Fallback Placeholder: Uses component's
placeholderprop as last resort - Custom Fallback: Uses
bindingOptions.fallbackif 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 removedonerrorand 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?
- 🔴 Live Data Binding Examples - See data binding in action
- 🧩 Component Overview - Learn which components support data binding
- 🎨 Theming - Use consistent styling with data-bound content
- 🏗️ Layout System - Create data-driven responsive layouts