Sections
A section is essentially a React
functional component. These sections are located in the sections
folder,
where each file represents a section. Within each file, the functional component must be exported as
the default export. The file name, without the extension, is used as the section’s name within Pages.
Sections are the building block of the pages. One or more section sit vertically one after another and make up the pages. Visually, this looks like this:
Here, the header, the footer, and the bluish background are part of the Layout.
The sections folder should not contain any nested folders. If you need common React components, you can store them in a separate folder, such as components, and then import them into your section components as needed.
A basic section
Here’s an example of a basic section:
import React from 'react';
const FeaturedProducts = () => {
return (
<section className="section">
<div className="container">
<header className="section-products-featured--header">
<h3>Explore Our Collection</h3>
</header>
<div className="products-list">
</div>
</div>
</section>
)
};
export default FeaturedProducts
Important: The React
component must be the default export from this file/module.
Section schema
Each Section should provide a schema if it requires dynamic values as props. A Section schema is the description of the props
and blocks
of that Section. They denote what type of dynamic data is required in the Section. In the page designer, this schema is used to
allow the theme users to choose their own values.
Both props
and blocks
are defined using a class named Prop
.
It has various aptly named properties that are used to define the types.
Available types:
Type | Code Example | Chained methods |
---|---|---|
Text | Prop.text() | .text() |
Number | Prop.number() | .min() .max() |
Boolean | Prop.boolean() | |
Image | Prop.image() | |
Range | Prop.range() | |
Choice | Prop.choice() | .option() |
Color | Prop.color() | |
URL | Prop.url() | |
Product | Prop.product() | .array() ( .array() -> .min() .max() ) |
Collection | Prop.collection() | .array() |
Article | Prop.article() | .array() |
Page | Prop.page() | .array() |
All types have these common chained methods: .label()
.default()
.hint()
props
Here’s an example schema:
import {Prop} from "builderoo"
export const props = {
title: Prop.text().label("Title"),
link: Prop.url(),
collection: Prop.collection().label("Collection")
}
// ...
// Component code
// ...
In this example title
, link
and collection
are props. They each have different types.
You can use these dynamic props in the Section component like this:
import {Prop} from "builderoo"
import ProductItem from "../components/product-item";
import {useProps} from "builderoo";
export const props = {
title: Prop.text().label("Title").default("Winter Products"),
link: Prop.url(),
collection: Prop.collection().label("Collection")
}
const FeaturedProducts = () => {
const {title, link, collection} = useProps()
return (
<section className="section">
<div className="container">
<header className="section-products-featured--header">
<h3>{title}</h3>
</header>
<div className="products-list">
{ collection && collection.products.map(product => (
<ProductItem product={product}/>
))}
</div>
</div>
</section>
)
};
export default FeaturedProducts
Now, users can edit these values in the Visual Editor.
Important: the prop schema must be defined as export const props = value
import {Link, Prop, useProps} from "builderoo"
export const props = {
// props
}
export default function HeroSection(){
const {x, y, z} = useProps<typeof props>()
// section content
}
blocks
Blocks are the building blocks of your theme’s sections. They allow you to group a set of properties that users can add to their sections. Each block represents a specific element or component within a section, such as a swiper, carousel, or any other customizable feature.
For example, let’s say you have a carousel. Each item of the carousel can have title, image, link etc. You can define a block for the carousel item and that block can be repeated dynamically according to the number of carousel items you need.
To define a custom block, you need to export a blocks object. This object contains the configuration for your block, including its properties and their types. Here’s an example of how to define a custom block:
import {Prop} from "builderoo"
// ...
// Component code
// ...
export const blocks = {
swiper: {
title: Prop.text(),
text: Prop.url(),
link: Prop.url(),
linkText: Prop.text().label("Text on link"),
image: Prop.image(),
_meta_: Prop.meta().label("Swiper").min(1).max(10)
},
"why-item": {
icon: Prop.text(),
title: Prop.text(),
subtitle: Prop.text(),
_meta_: Prop.meta().min(1).max(3)
}
// more blocks
}
In the above example swiper
and why-item
are the name of the blocks. You can define multiple blocks if you need.
Here’s an example usage:
import {useBlocks, Link} from "builderoo"
export const blocks = {
// blocks schema
}
export default function IntroSection() {
const blocks = useBlocks()
return (
<section className="section">
<div className="container">
<ul className="hero-swiper">
{ blocks.filter(name => name === "swiper").map((block, i) => (
<li key={i}>
<img src={block.props.image} />
<div>
<h3>{block.props.title}</h3>
<p>{block.props.text}</p>
</div>
<Link href={block.props.link}>{block.props.linkText}</Link>
</li>
))}
</ul>
</div>
<div className="container">
<ul className="why-choose-us">
{ blocks.filter(name => name === "why-item").map((block, i) => (
<li key={i}>
<i className={`icon-${block.props.icon}`}></i>
<div>
<h3>{block.props.title}</h3>
<p>{block.props.subtitle}</p>
</div>
</li>
))}
</ul>
</div>
</section>
);
}
and enjoy type safety and autocompletion in smart IDEs:
import {Link, Prop, useBlocks} from "builderoo"
export const blocks = {
// blocks schema
}
export default function IntoSection(){
const sectionBlocks = useBlocks<typeof blocks>()
}
initialBlocks
In prop definition, you can provide default values for each props like this
export const props = {
title: Prop.text().label("Title").default("Why Choose Us")
}
When you add the section to a page, these default values will be populated automatically.
This is also applicable to the block props. However, blocks
definition does not tell which
blocks should populate automatically and in which order. You can specify this by exporting initialBlocks
value like this
export const blocks = {
"why-item": {
icon: Prop.text().label("Icon").default("payment"),
title: Prop.text().label("Title").default("Easy Payments"),
subtitle: Prop.text().default("All payments are processed instantly over a secure payment protocol"),
}
}
export const initialBlocks = ["why-item", "why-item"]
The above example tells us to generate 2 blocks by default (when blocks
props are not defined in page json file.).
These 2 blocks will all have default values as defined line (3-5).
In the above example, both blocks will have the same value. You can change this behavior by specifying values for all the props of the corresponding block. For example:
export const initialBlocks = [
"why-item",
{
"name": "why-item",
"props": {
"icon": "shipping",
"title": "Fast Shipping For You",
"subtitle": "Exclusive shipping deals"
}
}
]
Now the first block will have default values but the second block will have custom values as defined above.
import type {InitialBlocks} from "builderoo"
export const blocks = {
// ...
// Blocks schema
// ...
}
export const initialBlocks: InitialBlocks<type of blocks> = [
// ...
// Initial blocks
// ...
]
loginRequired
If this section contains anything (such as order list or oder details) then export the following property. When users
navigate to a page that contains at least one section with loginRequired
set to true
, they’ll be redirected to the login page.
export const loginRequired = true | false
Editor support
Text props
can be made visually editable in the Theme Editor. To do this, use the Text
component. Here’s an example:
import {Prop, Text, useProps} from "builderoo"
import ProductItem from "../components/product-item";
export const props = {
title: Prop.text().label("Title")
}
export default function FeaturedProducts(){
const {title} = useProps()
return (
<section className="section">
<div className="container">
<header className="section-products-featured--header">
<h3 className="text-2xl">{title}</h3>
<Text as="h3" className="text-2xl" value={title} />
</header>
</div>
</section>
)
}
blocks
can also be edited in the Theme Editor by wrapping the block content with the Block
component. With this simple
change, blocks can be moved up/down/left/right, deleted etc visually in the Theme Editor. Here’s an example:
import {Block, useBlocks, Link, Text} from "builderoo"
export const blocks = {
// blocks schema
}
export default function IntroSection() {
const blocks = useBlocks()
return (
<section className="section">
<div className="container">
<ul className="hero-swiper">
{ blocks.filter(name => name === "swiper").map((block, i) => (
<Block key={block.key} block={block}>
<li>
<img src={block.props.image} />
<div>
<Text as="h3" value={block.props.title} />
<p>{block.props.text}</p>
</div>
<Link href={block.props.link}>{block.props.linkText}</Link>
</li>
</Block>
))}
</ul>
</div>
<div className="container">
<ul className="why-choose-us">
{ blocks.filter(name => name === "why-item").map((block, i) => (
<Block key={block.key} block={block}>
<li>
<i className={`icon-${block.props.icon}`}></i>
<div>
<h3>{block.props.title}</h3>
<p>{block.props.subtitle}</p>
</div>
</li>
</Block>
))}
</ul>
</div>
</section>
);
}
Important
The value
prop of the Text component must refer to an actual prop name from the prop/block definition.
For the following prop definition
export const props = {
title: Prop.text().label("Title"),
}
The following usage is correct
export default function Section(){
const {title} = useProps()
return <Text as="span" value={title} />
}
The following usage is also correct
export default function Section(){
const props = useProps()
return <Text as="span" value={props.title} />
}
For the following prop definition
export const props = {
title: Prop.text().label("Title"),
}
The following usage is incorrect because the value
prop does not refer to title
exactly.
export default function Section(){
const {title} = useProps()
const myTitle = title
return <Text as="span" value={myTitle} />
}
Similar rules apply for props inside a block as well.
For the Text
component to work with block props, the Text
component must be inside the corresponding Block
component.