JSON RTE Registry
JSON RTE Registry
registerJsonRte
The registerJsonRte method registers custom element types (blocks) and text wrappers (inline marks) for JSON RTE content.
Use Case: Extend the default rich-text rendering with branded components, custom formatting, and visual effects.
Parameters:
| Name | Type | Description |
| config | IJsonToHtmlOptions | Configuration object for custom JSON RTE rendering. |
import { registerJsonRte } from '@contentstack/studio-react';
registerJsonRte({
customElementTypes: {
// Custom block-level elements
infoBox: (attrs, child, jsonBlock, extraProps) => {
return `<div class="info-box" style="padding: 1rem; background-color: #e3f2fd; border-left: 4px solid #2196f3;">${child}</div>`;
},
callout: (attrs, child, jsonBlock, extraProps) => {
const type = jsonBlock.attrs?.type || 'info';
const colors = {
info: '#e3f2fd',
warning: '#fff3e0',
error: '#ffebee',
success: '#e8f5e9'
};
return `<div class="callout callout-${type}" style="padding: 1rem; background-color: ${colors[type]}; border-radius: 4px; margin: 1rem 0;">${child}</div>`;
}
},
customTextWrapper: {
// Custom inline text formatting
highlight: (child, value) => {
return `<span class="highlight" style="background-color: #ffeb3b; padding: 2px 4px;">${child}</span>`;
},
color: (child, value) => {
return `<span class="text-color" style="color: ${value};">${child}</span>`;
},
code: (child, value) => {
return `<code class="inline-code" style="background-color: #f5f5f5; padding: 2px 4px; border-radius: 3px; font-family: monospace;">${child}</code>`;
}
},
allowNonStandardTypes: true
});Configuration Options
The configuration options let developers control how JSON RTE content is converted to HTML. You can define custom elements, text wrappers, and allow non-standard types to extend rendering behavior.
customElementTypes (IJsonToHtmlElementTags)
The customElementTypes option defines the block-level elements you want to support in rich text.
Function Signature
Parameters
| Name | Type | Description |
| attrs | string | HTML attributes represented as a string. |
| child | string | The rendered inner HTML content of the element. |
| jsonBlock | object | The full JSON block object. Use jsonBlock.attrs to access attributes. |
| extraProps | object (optional) | Additional context props passed from the rendering environment. |
customElementTypes: {
// Custom info box component
infoBox: (attrs, child, jsonBlock) => {
const title = jsonBlock.attrs?.title || 'Information';
const icon = jsonBlock.attrs?.icon || 'ℹ️';
return `
<div class="info-box" style="border: 1px solid #ddd; border-radius: 8px; padding: 1rem; margin: 1rem 0;">
<div style="display: flex; align-items: center; margin-bottom: 0.5rem;">
<span style="font-size: 1.2rem; margin-right: 0.5rem;">${icon}</span>
<strong>${title}</strong>
</div>
<div>${child}</div>
</div>
`;
},
// Custom quote component
quote: (attrs, child, jsonBlock) => {
const author = jsonBlock.attrs?.author || 'Unknown';
const source = jsonBlock.attrs?.source || '';
return `
<blockquote class="custom-quote" style="border-left: 4px solid #007bff; padding-left: 1rem; margin: 1rem 0; font-style: italic;">
<div>${child}</div>
<footer style="margin-top: 0.5rem; font-size: 0.9rem; color: #666;">
— ${author}${source ? `, ${source}` : ''}
</footer>
</blockquote>
`;
}
}customTextWrapper (IJsonToHtmlTextTags)
The customTextWrapper option defines inline text wrappers or marks used for applying formatting and effects to text within JSON RTE content.
Use Case: Enables custom styles such as highlights, keyboard inputs, or branded inline elements in rich-text fields.
Function Signature
(child: any, value: any) => string
Parameters
| Name | Type | Description |
| child | string | The text content to wrap. |
| value | any | The attribute value applied to the wrapper (for example, a color code, style, or effect). |
Example
customTextWrapper: {
// Highlight text with custom colors
highlight: (child, value) => {
const colors = {
yellow: '#ffeb3b',
green: '#4caf50',
blue: '#2196f3',
red: '#f44336'
};
const color = colors[value] || value;
return `<span class="highlight" style="background-color: ${color}; padding: 2px 4px; border-radius: 3px;">${child}</span>`;
},
// Custom text styling
style: (child, value) => {
const styles = {
bold: 'font-weight: bold;',
italic: 'font-style: italic;',
underline: 'text-decoration: underline;',
strikethrough: 'text-decoration: line-through;'
};
const style = styles[value] || '';
return `<span style="${style}">${child}</span>`;
},
// Custom font sizes
fontSize: (child, value) => {
return `<span style="font-size: ${value}px;">${child}</span>`;
}
}allowNonStandardTypes (boolean)
The allowNonStandardTypes option enables the use of non-standard element types in JSON RTE content.
Use Case:
- Custom Components: Add branded elements such as info boxes, callouts, or product cards.
- Enhanced Text: Format text with highlights, colors, or special fonts.
- Interactive Elements: Insert interactive components, like buttons or widgets, into rich text.
- Brand Consistency: Ensure rich text content aligns with your design system and styling standards.
Real World Example
import { registerJsonRte } from '@contentstack/studio-react';
// Register custom JSON RTE components for a marketing website
registerJsonRte({
customElementTypes: {
// Product showcase within rich text
productShowcase: (attrs, child, jsonBlock) => {
const product = jsonBlock.attrs;
return `
<div class="product-showcase" style="
border: 2px solid #e0e0e0;
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
">
<div style="display: flex; align-items: center; gap: 1rem;">
<img src="${product.image || '/placeholder.jpg'}"
alt="${product.name || 'Product'}"
style="width: 80px; height: 80px; border-radius: 8px; object-fit: cover;">
<div>
<h4 style="margin: 0 0 0.5rem 0; color: #2c3e50;">${product.name || 'Product Name'}</h4>
<p style="margin: 0 0 0.5rem 0; color: #7f8c8d;">${product.description || 'Product description'}</p>
<div style="font-size: 1.25rem; font-weight: bold; color: #e74c3c;">
$${product.price || '0.00'}
</div>
</div>
</div>
${child}
</div>
`;
},
// Testimonial block
testimonial: (attrs, child, jsonBlock) => {
const testimonial = jsonBlock.attrs;
return `
<div class="testimonial" style="
background-color: #f8f9fa;
border-left: 4px solid #007bff;
padding: 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
">
<div style="font-style: italic; margin-bottom: 1rem; color: #495057;">
"${child}"
</div>
<div style="display: flex; align-items: center; gap: 0.5rem;">
<img src="${testimonial.avatar || '/default-avatar.jpg'}"
alt="${testimonial.author || 'Author'}"
style="width: 40px; height: 40px; border-radius: 50%; object-fit: cover;">
<div>
<strong style="color: #2c3e50;">${testimonial.author || 'Author Name'}</strong>
${testimonial.title ? `<br><span style="color: #6c757d; font-size: 0.9rem;">${testimonial.title}</span>` : ''}
</div>
</div>
</div>
`;
},
// Code block with syntax highlighting
codeBlock: (attrs, child, jsonBlock) => {
const language = jsonBlock.attrs?.language || 'text';
return `
<div class="code-block" style="
background-color: #2d3748;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
overflow-x: auto;
">
<div style="
color: #e2e8f0;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.9rem;
line-height: 1.5;
">
<div style="
color: #a0aec0;
border-bottom: 1px solid #4a5568;
padding-bottom: 0.5rem;
margin-bottom: 1rem;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.05em;
">
${language}
</div>
<pre style="margin: 0; white-space: pre-wrap;">${child}</pre>
</div>
</div>
`;
}
},
customTextWrapper: {
// Brand colors for text
brandColor: (child, value) => {
const brandColors = {
primary: '#007bff',
secondary: '#6c757d',
success: '#28a745',
danger: '#dc3545',
warning: '#ffc107',
info: '#17a2b8'
};
const color = brandColors[value] || value;
return `<span style="color: ${color}; font-weight: 500;">${child}</span>`;
},
// Custom text effects
textEffect: (child, value) => {
const effects = {
glow: 'text-shadow: 0 0 10px currentColor;',
shadow: 'text-shadow: 2px 2px 4px rgba(0,0,0,0.3);',
outline: 'text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;'
};
const effect = effects[value] || '';
return `<span style="${effect}">${child}</span>`;
}
},
allowNonStandardTypes: true
});Conditional Props
Conditional props are component props whose values depend on the values of other props. They enable components to change behavior or configuration dynamically, based on user selections or predefined logic.
Use Case: Show or modify a prop’s value only when another related prop meets a certain condition — for example, displaying a "link URL" field only when "link enabled" is set to true.
Example
props: {
showAdvanced: {
type: "boolean",
displayName: "Show Advanced Options",
defaultValue: false
},
advancedConfig: {
type: "object",
displayName: "Advanced Configuration",
defaultValue: {},
// This prop will only be shown when showAdvanced is true
// (handled automatically by the Studio)
}
}Binding Support
Binding Support allows all component props to connect to external data sources using data binding.
Use Case: Dynamically populate component values such as text, images, or links by binding them to CMS entries, API responses, or environment variables within Studio.
Styles Configuration
The styles object defines the styling options available for your component, enabling customization of its visual appearance.
Example
styles: {
// Default style group
default: {
styleSections: ["size", "spacing", "background", "border"],
defaultClasses: ["my-component", "rounded"],
defaultStyles: { padding: "1rem" },
displayName: "Default Styles"
},
// Custom style group
custom: {
styleSections: ["typography", "transform"],
defaultClasses: ["custom-text"],
defaultStyles: { fontSize: "16px" },
displayName: "Custom Styles"
}
}Available Style Sections
| Section | Description |
| class | Custom CSS classes. |
| size | Width, height, min/max dimensions. |
| spacing | Margin and padding. |
| position | Position and z-index. |
| visibility | Display and opacity. |
| layout | Flexbox and grid properties. |
| typography | Font properties and text alignment. |
| transform | Transform properties. |
| media | Media query styles. |
| background | Background properties. |
| shadow | Box and text shadow. |
| effect | Filter and backdrop-filter. |
| overflow | Overflow properties. |
| border | Border properties. |
| responsive | Responsive design utilities. |
Style Section Categories
| Category | Description |
| block | All block-level styling options. |
| text | Typography-focused styling options. |
Registry Options
The registerComponents configuration object controls built-in component availability, user overrides, and debug logging behavior.
allowedBuiltInComponents
The allowedBuiltInComponents option controls the built-in components available in the registry.
Type: boolean | string[]
Values:
- true: Enable all built-ins (default)
- false: Disable all built-ins
- string[]: Enable only specific built-in types
overrideDefaultComponents
The overrideDefaultComponents option determines if user components override built-in components with the same type identifier.
Type: boolean
Values:
- false: Prevent overriding built-ins (default)
- true: Allow user components to override
debug
The debug option enables debug logging for troubleshooting during component registration.
Type: boolean
Values:
- false: Disable logging (default)
- true: Enable logging
Usage Example
// Basic component registration
registerComponents([
{
type: "hero-section",
component: HeroSection,
displayName: "Hero Section",
description: "A prominent section for main content",
sections: ["Custom Components"]
}
]);
// Advanced component with full configuration
registerComponents([
{
type: "product-card",
component: ProductCard,
displayName: "Product Card",
description: "Display product information in a card format",
sections: ["Custom Components", "E-commerce"],
wrap: false,
thumbnailUrl: "/images/product-card-thumbnail.png",
hideFromContentCreators: false,
hideFromComponentList: false,
props: {
productId: {
type: "string",
displayName: "Product ID",
placeholder: "Enter product ID"
},
showPrice: {
type: "boolean",
displayName: "Show Price",
defaultValue: true
}
},
styles: {
default: {
styleSections: ["size", "spacing", "background", "border"],
defaultClasses: ["product-card"],
displayName: "Card Styles"
},
content: {
styleSections: ["typography"],
defaultClasses: ["product-content"],
displayName: "Content Styles"
}
}
}
]);
// Component with validation
registerComponents([
{
type: "contact-form",
component: ContactForm,
displayName: "Contact Form",
description: "A form for collecting contact information",
sections: ["Forms"],
props: {
email: {
type: "string",
displayName: "Email",
placeholder: "Enter email address"
}
}
}
]);registerComponents
The registerComponents method makes custom React components available in Studio. Once registered, these components can be added, configured, and styled by content creators within the Studio interface alongside built-in components.
Returns
Type void
Parameters
| Name | Type | Description |
| componentConfig (required) | Component configuration object | One or more component configurations to register. |
| options | Optional registry configuration | Controls built-ins, overrides, and debugging. |
Example
import { registerComponents } from '@contentstack/studio-react';
registerComponents(componentConfig, options);Best Practices
- Performance: Keep custom element renders lightweight and avoid complex DOM manipulation.
- Accessibility: Use semantic HTML and include appropriate ARIA attributes to ensure custom elements are usable with assistive technologies.
- Responsiveness: Apply CSS and layout techniques that adapt well across devices.
- Consistency: Align custom elements with your design system to maintain a cohesive appearance across content.
- Testing: Validate custom elements with varied content scenarios, edge cases, and real-world usage to ensure stability and reliability.
Note
- Unique type Each component requires a unique identifier.
- System protection Built-in components cannot be overridden.
- Validation Props can include custom validation rules.
- Styling Components have access to design tokens and CSS-in-JS.
- Interactivity Use useHiddenElementNotification with wrap: false for interactive components.
- Performance Components are registered once and cached for efficiency.