Components:Tutorial: Input Component - bettyblocks/cli GitHub Wiki

In this tutorial we will create an input Component that can be used in the Betty Blocks Page Builder. This tutorial assumes that you've gone ahead and set up your own Component Set.

Steps

To create our Component, we'll follow these steps:

  1. Prepare the Prefab.
  2. Prepare the Component.
  3. Write the JSX.
  4. Add the Component to the Prefab.
  5. Allow the Component inside other Components.
  6. Test your Component.
  7. Customize Component Page Builder behavior.
  8. Add Component Options.

1. Prepare the Prefab

If you are unsure what a Prefab is, find out here.

Inside ./src/prefabs, add a file called input.js containing the following:

(() => ({
  name: "Input",
}))();

Name

The Prefab currently only contains a name, Input, which corresponds to the filename input.js. We'll add a couple more fields so that it can be used in the Page Builder.

Icon

First off, let's choose the icon to represent this Prefab in the Page Builder sidebar. A list of available icons can be found here. Let's go with "TextInputIcon" for now:

(() => ({
  name: "Input",
  icon: "TextInputIcon"
}))();

Category

We need to supply a category to determine how the Prefab will be grouped. For our input element, the "FORM" category makes sense:

(() => ({
  name: "Input",
  icon: "TextInputIcon",
  category: "FORMS"
}))();

Structure

The structure determines which Components belong to the Prefab, along with their options. For now, we add an empty list. We will return to this value after we've prepared the Component.

(() => ({
  name: "Input",
  icon: "TextInputIcon",
  category: "FORMS",
  structure: []
}))();

2. Prepare the Component

A Prefab without Components is literally useless. Let's fix this by adding a file called input.js to ./src/components containing the following:

(() => ({
  name: "Input"
}))();

Name

As with the Prefab, we start with just the name, which likewise mirrors the Component filename. This name can later be used to reference this Component inside the Prefab structure.

Type

The type can be added to the list of allowed types in another Component. We recommend using the uppercased Component name as the value:

(() => ({
  name: "Input",
  type: "INPUT"
}))();

Allowed Types

It doesn't make much sense yet for our input Component to contain children, so let's go ahead and add an empty list.

(() => ({
  name: "Input",
  type: "INPUT",
  allowedTypes: []
}))();

Orientation

In this case, we want our input Components to be stacked vertically, so let's go with a horizontal drop indicator:

(() => ({
  name: "Input",
  type: "INPUT",
  allowedTypes: [],
  orientation: "HORIZONTAL"
}))();

Styles

For now, add an empty curried function as the styles key. Don't worry for now if this looks funky to you, we'll come back to this later:

(() => ({
  name: "Input",
  type: "INPUT",
  allowedTypes: [],
  orientation: "HORIZONTAL",
  styles: () => () => ({})
}))();

3. Write the JSX

Now that our Prefab and Component are configured, let's get down to business and write the actual mark-up. Add JSX to the Component (./src/components/input.js) so it ends up looking like this:

(() => ({
  name: "Input",
  type: "INPUT",
  allowedTypes: [],
  orientation: "HORIZONTAL",
  styles: () => () => ({}),
  jsx: <input type="text" />
}))();

4. Add the Component to the Prefab

To make the Component available inside the Page Builder, we add it to the Prefab we made earlier (./src/prefabs/input.js):

(() => ({
  name: "Input",
  icon: "TextInputIcon",
  category: "FORMS",
  structure: [
    {
      name: "Input",
      options: [],
      descendants: [],
    },
  ],
}))();

Structure

The important part is that the name inside the first structure object ("Input") matches the name in ./src/components/input.js. Options and descendants have been left empty. We'll get to those in a bit.

5. Allow the Component inside other Components

Before we can use the Component inside the Page Builder, we'll need to specify which of the other Components may serve as a parent. We do this by adding the Component type to the list of allowed types in the desired parent Component, ie. this container Component:

(() => ({
  name: 'Container',
  allowedTypes: [
    "INPUT",
  ],
  // omitted for brevity
}

6. Test the Component

Let's see the result of our work so far. Open the root directory of your Component Set in your shell, and tell bb to build and serve:

$ bb components build
Built component set.

$ bb components serve
Serving "Your Awesome" Component Set at http://localhost:5001

Load your Component Set into the Page Builder as described here. After refreshing the page, the input Component should be available in the sidebar. Now drag a container Component onto the canvas, and add an input Component by dragging it onto the container.

If all went well, you should be seeing something like this:

The input Component on the canvas.

After clicking the Play button, your Component will be rendered:

The input Component in the application.

7. Customize Component Page Builder behavior

You might have noticed that you're able to type inside the input while designing your page, whereas you only want to enable this inside the actual Application you're building. Let's fix this inside the JSX of the input Component (./src/components/input.js) with the help of a Component Helper:

(() => ({
  // omitted for brevity
  jsx: <input type="text" readOnly={B.env === 'dev'} />
}))();

What we're saying is that the input should be read-only when the Component is shown inside the Page Builder (as opposed to your Application).

8. Add Component Options

When we click the Component on the Page Builder canvas, the sidebar is empty. This is because we haven't added any Options.

Placeholder

One thing we would like to make configurable is the placeholder text.

Add an option to the Component Prefab (./src/prefabs/input.js) structure:

  // omitted for brevity
  structure: [
    {
      name: "Input",
      options: [
        {
          key: "placeholder",
          label: "Placeholder",
          type: "TEXT",
          value: "",
        },
      ],
      descendants: [],
    },
  ],
  // ...

If you drag the input Component on the canvas again and click it, you should see the placeholder Option in the sidebar:

The input Component on the canvas.

Right now the Option doesn't do anything. The value can be changed, but it isn't used. Go back to the Component (./src/prefabs/input.js) and change the JSX so it looks like this:

  jsx: (
    <input
      type="text"
      readOnly={B.env === 'dev'}
      placeholder={options.placeholder}
    />
  ),

The placeholder attribute will now use the value of the Option:

The input Component with the placeholder Option.

Leads to:

The input Component on with placeholder.

Name

Our input needs a name attribute in the context of a form. In ./src/prefabs/input.js, add an Option, just like we did for placeholder:

  // omitted for brevity
        {
          key: "name",
          label: "Name",
          type: "TEXT",
          value: "",
        },
  // ...

Use the name Option value to set the name attribute in the Component (./src/components/input.js):

    <input
      type="text"
      readOnly={B.env === 'dev'}
      placeholder={options.placeholder}
      name={options.name}
    />

The effect of the name value is not immediately visible in the Application, but will come in handy later when we have to reference the input.

Label

Let's add a label Option, so we can specify what our input field means. In ./src/prefabs/input.js:

  // omitted for brevity
  structure: [
    {
      name: "Input",
      options: [
        {
          key: "label",
          label: "Label",
          type: "TEXT",
          value: "",
        },
      ],
      descendants: [],
    },
  ],
  // ...

Change the Component (./src/components/input.js) mark-up accordingly:

    <label htmlFor={options.name}>
      <span>{options.label}</span>
      <input
        type="text"
        readOnly={B.env === 'dev'}
        placeholder={options.placeholder}
        name={options.label}
        id={options.label}
      />
    </label>
⚠️ **GitHub.com Fallback** ⚠️