Model fields are useful not only for storing pure data, but also to define any visual settings affecting a component's rendering that content editors should be able to control.

Component code then has access to the user's choices through the properties of the content object passed to them as argument - as with any other content field.

There are two ways to allow styling through fields. You can use both as approriate.

Using regular fields

In the models we provide for our components you'll find many fields used for controlling visual rendering. Often, we use enum fields that provide a fixed set of values to choose from, as the matching component's code supports exactly these values.

To clearly mark these fields as styling-related, these are typically grouped separately than content fields using field groups. Each field group appears as a collapsible section in the content pane:

Enum field used for styling

There's another option, though, to help you define common styling options quickly and robustly, and allow content editors to modify them in a more visual, immediate fashion: style fields.

Using style-type fields

To make visual editing of common CSS properties easier, we've picked a subset of these properties and built a dedicated panel in the visual editor to let the user edit them, with the proper controls for each. This is supported both at the component level and for specific fields.

Through the model definition, you are in full control of whether and which properties to let the user control, and which values are valid for each property.

Here's how this panel appears for a selected component in the visual editor, with only the options defined in the model of that component.

Styles in the visual editor

How it works

In relevant models, add a single field of type style (the name of this field is up to you). This field type requires configuration under its styles property.

Here is an example configuration, in the model file of an imaginary section called StyledSection:

name: StyledSection
# ...
fields:
  - type: string
    name: title
  - type: string
    name: subtitle
  - type: style
    name: styles
    styles:
      title:
        textAlign: ['left', 'center', 'right']
        fontWeight: [100, 400, 700]
      subtitle:
        textAlign: ['left', 'center', 'right', 'justify']
        fontStyle: ['italic', 'normal']
      self:
        backgroundColor:
          - color: '#000000'
            value: 'bg-black'
          - color: '#fca5a5'
            value: 'bg-red-300'

For each model field whose rendering style is to be configurable, there's an entry with that field name - see title and subtitle above. Under each field entry, there's an item for each styling option that should be available, and the valid values for it.

For styling options at the model level (i.e. which should affect the whole component rather than the rendering of a single field), use the entry name self as above.

Here's the expected structure of the styles object in a more abstract form:

# In a model
fields:
  ...
  - type: style
    name: <some_field_name>
    styles:
      self:
        <styleName>: <styleValues>
        <styleName>: <styleValues>
      <model_field_name>:
        <styleName>: <styleValues>
        <styleName>: <styleValues>
      <model_field_name>:
        ...

How styles are stored

Continuing with the above example of the StyledSection section, let's assume a content editor now adds this section to one of the site's pages, and sets the appropriate values for its content and style fields.

Here's how the section's data will be stored - within the file of its parent page:

{
  "title": "foo",
  "subtitle": "bar",
  "styles": {
    "title": {
      "textAlign": "center",
      "fontWeight": "bold"
    },
    "subtitle": {
      "textAligh": "right",
      "fontStyle": "italic"
    },
    "self": {
      "backgroundColor": "bg-red-300"
    }
  }
}

Whenever the StyledSection React component code is then called to render that content (as part of rendering the page), this is the object it will receive in the arguments.

See the reference of supported styling properties for the full list of supported CSS properties and the allowed values for each.

Mapping values to class names

In each of our themes, you'll find a ready-made helper function to map from stored values to Tailwind utility class names. You can use or extend this helper for your own components as well.

Here's an edited excerpt from the PostFeedSection component in our "Startup" theme. This excerpt focuses on the function which renders that section's header: its title and subtitle fields.

Note how mapStyles() is used in conjunction with the infamous classnames helper to combine fixed class names with user-configurable ones.

import * as React from 'react';
import classNames from 'classnames'
import { mapStylesToClassNames as mapStyles } from '../../../utils/map-styles-to-class-names';
// ...

function postFeedHeader(props) {
  const styles = props.styles || {}
  return (
    <div>
      {props.title && (
        <h2 data-sb-field-path=".title" 
            className={classNames('text-3xl', mapStyles(styles.title))}>
          {props.title}
        </h2>
      )}
      {props.subtitle && (
        <p data-sb-field-path=".subtitle"
           className={classNames('text-lg', mapStyles(styles.subtitle))}>
          {props.subtitle}
        </p>
      )}
    </div>
  )
}
// ...

Available styling options

For a reference of available styling properties and their allowed values, see here.

Next up: How to use content presets with components.