Component Example
This guide provides a complete, working example of a Hero component with all required files and best practices.
Component Overview
The Hero component displays a large banner with:
- Background image
- Heading and subheading
- Optional call-to-action button
- Configurable text alignment
- Responsive design
File Structure
hero/
├── details.json
├── dialog.json
├── component.html
├── component.css
└── variables.json
details.json
{
"name": "Hero Banner",
"description": "A large hero banner with image, heading, and call-to-action",
"purpose": "Display prominent content at the top of pages to capture attention and drive action",
"optionsDescription": "Configure background image, heading, subheading, text alignment, and optional button with link"
}
dialog.json
{
"schemaVersion": "1.0",
"fieldGroups": [
{
"label": "Content",
"fields": [
{
"type": "text",
"name": "heading",
"label": "Heading",
"required": true,
"maxLength": 100,
"placeholder": "Enter a compelling heading",
"defaultValue": "Welcome to Our Site"
},
{
"type": "textarea",
"name": "subheading",
"label": "Subheading",
"required": false,
"rows": 3,
"maxLength": 200,
"placeholder": "Enter a subheading (optional)"
},
{
"type": "image",
"name": "backgroundImage",
"label": "Background Image",
"required": true,
"defaultValue": {
"src": "",
"alt": "Hero background"
}
}
]
},
{
"label": "Call to Action",
"fields": [
{
"type": "boolean",
"name": "showButton",
"label": "Show Button",
"defaultValue": false
},
{
"type": "text",
"name": "buttonText",
"label": "Button Text",
"required": false,
"maxLength": 30,
"defaultValue": "Learn More",
"showIf": {
"field": "showButton",
"equals": true
}
},
{
"type": "pageLink",
"name": "buttonLink",
"label": "Button Link",
"required": false,
"showIf": {
"field": "showButton",
"equals": true
}
}
]
},
{
"label": "Styling",
"fields": [
{
"type": "select",
"name": "textAlignment",
"label": "Text Alignment",
"required": true,
"defaultValue": "center",
"options": [
{ "value": "left", "label": "Left" },
{ "value": "center", "label": "Center" },
{ "value": "right", "label": "Right" }
]
},
{
"type": "select",
"name": "overlayOpacity",
"label": "Overlay Opacity",
"required": true,
"defaultValue": "medium",
"options": [
{ "value": "light", "label": "Light (20%)" },
{ "value": "medium", "label": "Medium (40%)" },
{ "value": "dark", "label": "Dark (60%)" }
]
}
]
}
]
}
component.html
<section class="hero hero-align-{{textAlignment}}">
<div class="hero-background">
<img src="{{backgroundImage.src}}" alt="{{backgroundImage.alt}}" class="hero-image" />
<div class="hero-overlay hero-overlay-{{overlayOpacity}}"></div>
</div>
<div class="hero-content">
<div class="hero-text">
<h1 class="hero-heading">{{heading}}</h1>
{{#if subheading}}
<p class="hero-subheading">{{subheading}}</p>
{{/if}}
{{#if showButton}}
{{#if buttonLink}}
<div class="hero-actions">
<a href="{{buttonLink}}" class="hero-button">{{buttonText}}</a>
</div>
{{/if}}
{{/if}}
</div>
</div>
</section>
component.css
.hero {
position: relative;
min-height: var(--hero-min-height, 500px);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.hero-background {
position: absolute;
inset: 0;
z-index: 0;
}
.hero-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.hero-overlay {
position: absolute;
inset: 0;
background-color: rgba(0, 0, 0, 0.4);
}
.hero-overlay-light {
background-color: rgba(0, 0, 0, 0.2);
}
.hero-overlay-medium {
background-color: rgba(0, 0, 0, 0.4);
}
.hero-overlay-dark {
background-color: rgba(0, 0, 0, 0.6);
}
.hero-content {
position: relative;
z-index: 1;
width: 100%;
max-width: var(--container-max-width);
padding: var(--spacing-2xl) var(--container-padding);
}
.hero-text {
color: white;
}
.hero-align-left .hero-text {
text-align: left;
}
.hero-align-center .hero-text {
text-align: center;
}
.hero-align-right .hero-text {
text-align: right;
}
.hero-heading {
font-family: var(--font-family-heading);
font-size: 3rem;
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin: 0 0 var(--spacing-md) 0;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.hero-subheading {
font-family: var(--font-family-base);
font-size: var(--font-size-xl);
line-height: var(--line-height-base);
margin: 0 0 var(--spacing-xl) 0;
opacity: 0.95;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.hero-actions {
margin-top: var(--spacing-xl);
}
.hero-button {
display: inline-block;
padding: var(--spacing-md) var(--spacing-xl);
background-color: var(--color-primary);
color: white;
font-family: var(--font-family-base);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
text-decoration: none;
border-radius: var(--border-radius-md);
transition: background-color 0.2s ease, transform 0.2s ease;
box-shadow: var(--shadow-md);
}
.hero-button:hover {
background-color: var(--color-secondary);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.hero-button:active {
transform: translateY(0);
}
/* Responsive adjustments */
@media (max-width: 767px) {
.hero {
min-height: var(--hero-min-height-mobile, 400px);
}
.hero-heading {
font-size: 2rem;
}
.hero-subheading {
font-size: var(--font-size-lg);
}
.hero-content {
padding: var(--spacing-xl) var(--container-padding);
}
}
@media (min-width: 768px) and (max-width: 1023px) {
.hero-heading {
font-size: 2.5rem;
}
}
variables.json
{
"variables": [
{
"name": "--hero-min-height",
"category": "layout",
"description": "Minimum height of hero banner on desktop",
"defaultValue": "500px"
},
{
"name": "--hero-min-height-mobile",
"category": "layout",
"description": "Minimum height of hero banner on mobile devices",
"defaultValue": "400px"
}
]
}
Packaging the Component
Create a zip file:
zip -r hero.zip hero/
Or on Windows:
Compress-Archive -Path hero -DestinationPath hero.zip
Uploading the Component
- Navigate to Components in the Admin Tool
- Click Upload Component
- Select hero.zip
- Wait for validation
- Review the validation results
- Click Confirm Upload
Testing the Component
Create a Test Page
- Navigate to Sites → Select a site → Pages
- Click Create Page
- Fill in page details and select a template
- Click Create
Add the Hero Component
- In the page editor, find the Hero Banner in the component palette
- Drag it into a content zone
- Click the component to open the property dialog
- Fill in the fields:
- Heading: "Welcome to Our Site"
- Subheading: "Discover amazing content and features"
- Background Image: Upload an image
- Show Button: Enable
- Button Text: "Get Started"
- Button Link: Select a page
- Text Alignment: Center
- Overlay Opacity: Medium
- Click Save
Preview and Publish
- Check the live preview to see the component
- Test different field combinations
- Test on mobile, tablet, and desktop
- Click Publish when satisfied
Customization Examples
Different Overlay Opacities
Users can choose from three overlay opacity levels:
- Light (20%): For bright images where text is still readable
- Medium (40%): Balanced overlay for most images
- Dark (60%): For very bright images or when maximum text contrast is needed
Text Alignment Options
Users can align text left, center, or right:
- Left: Traditional alignment, good for longer text
- Center: Balanced, works well for short, impactful messages
- Right: Unique alignment, creates visual interest
Responsive Behavior
The component automatically adapts to different screen sizes:
- Mobile (<768px): Smaller heading, reduced padding, shorter min-height
- Tablet (768-1023px): Medium heading size
- Desktop (≥1024px): Full-size heading and spacing
Best Practices Demonstrated
Accessibility
- Alt text: Background image has alt text
- Semantic HTML: Uses <section>, <h1>, <p>, <a>
- Color contrast: Dark overlay ensures text is readable
- Keyboard navigation: Button is a standard <a> element
Performance
- Optimized CSS: Uses efficient selectors
- CSS variables: Leverages design variables for consistency
- Responsive images: Uses object-fit: cover for proper scaling
- Minimal JavaScript: No JavaScript required
User Experience
- Clear labels: Dialog fields have descriptive labels
- Sensible defaults: All fields have appropriate default values
- Conditional fields: Button fields only show when button is enabled
- Visual feedback: Button has hover and active states
Maintainability
- Organized CSS: Logical grouping of styles
- Consistent naming: Clear, descriptive class names
- Documented variables: Custom variables have clear descriptions
- Modular design: Component is self-contained
Variations
Hero with Video Background
To create a video background variant, modify component.html:
<section class="hero hero-align-{{textAlignment}}">
<div class="hero-background">
{{#if videoUrl}}
<video class="hero-video" autoplay loop muted playsinline>
<source src="{{videoUrl}}" type="video/mp4">
</video>
{{/if}}
{{#unless videoUrl}}
<img src="{{backgroundImage.src}}" alt="{{backgroundImage.alt}}" class="hero-image" />
{{/unless}}
<div class="hero-overlay hero-overlay-{{overlayOpacity}}"></div>
</div>
<!-- Rest of the component -->
</section>
Add a videoUrl field to dialog.json:
{
"type": "text",
"name": "videoUrl",
"label": "Video URL (optional)",
"required": false,
"placeholder": "https://example.com/video.mp4"
}
Hero with Multiple Buttons
To support multiple buttons, add additional button fields:
{
"type": "text",
"name": "secondaryButtonText",
"label": "Secondary Button Text",
"required": false,
"showIf": {
"field": "showButton",
"equals": true
}
}
Related Topics
- Component Structure — Component file requirements
- Dialog Schema — Field type reference
- Templating Syntax — Template marker syntax
- Design Variables — Using design variables
- Validation Rules — Validation requirements