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:

Layout

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:

sections/FeaturedProducts.jsx
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:

TypeCode ExampleChained methods
TextProp.text().text()
NumberProp.number().min() .max()
BooleanProp.boolean()
ImageProp.image()
RangeProp.range()
ChoiceProp.choice().option()
ColorProp.color()
URLProp.url()
ProductProp.product().array()   ( .array() -> .min() .max() )
CollectionProp.collection().array()
ArticleProp.article().array()
PageProp.page().array()

All types have these common chained methods: .label() .default() .hint()

props

Here’s an example schema:

sections/FeaturedProducts.jsx
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:

sections/FeaturedProducts.jsx
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:

sections/Intro.jsx
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:

sections/Intro.jsx
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:

sections/FeaturedProducts.jsx
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:

sections/Intro.jsx
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.