--- title: Create a custom control category: Sidebar controls in depth order: 8 status: published summary: Create your own sideEditProp UI when the built-in controls are not enough for the editing experience you want. estimatedTime: 9 min keywords: sideeditprops custom control component onChange isValid custom knob --- In this how-to, you'll learn how to create a custom sidebar control with `SideEditPropType.Custom`. This is the escape hatch for cases where the built-in controls are not enough. Docs reference: [Sidebar controls](https://docs.reactbricks.com/bricks/schema/side-edit-props/#custom-components) ## When a custom control makes sense Reach for a custom control when editors need a specialized UI such as: - a compound spacing picker - a map-based location picker - a preset picker with thumbnails - a custom token selector tied to your design system Before using a custom control, it is worth checking whether `Select`, `Autocomplete`, `Image`, or `Relationship` already covers the use case. ## The 2 required pieces A custom side edit prop needs: 1. a `type: types.SideEditPropType.Custom` 2. a `component` function that renders the editing UI React Bricks passes the component: - `value`: the current value of the prop - `onChange`: the function you call when your custom control should save a new value - `isValid`: whether the current value passes validation, useful for your custom UI to show an error state ## Example This example creates a tiny preset picker for section spacing: ```tsx {71,72} import clsx from 'clsx' import { Text, types } from 'react-bricks/rsc' type SpacingPreset = 'compact' | 'comfortable' | 'spacious' interface SectionBlockProps { title: types.TextValue spacing: SpacingPreset } const spacingClasses: Record = { compact: 'py-6', comfortable: 'py-12', spacious: 'py-20', } const SpacingControl = ({ value, onChange, isValid, }: { value?: SpacingPreset onChange: (value: SpacingPreset) => void isValid: boolean }) => { const options: SpacingPreset[] = ['compact', 'comfortable', 'spacious'] return (
{options.map((option) => ( ))}
) } const SectionBlock: types.Brick = ({ title, spacing }) => { return (

{children}

} />
) } SectionBlock.schema = { name: 'section-block', label: 'Section Block', getDefaultProps: () => ({ title: 'A section with spacing presets', spacing: 'comfortable', }), sideEditProps: [ { name: 'spacing', label: 'Spacing', type: types.SideEditPropType.Custom, component: SpacingControl, validate: (value) => ['compact', 'comfortable', 'spacious'].includes(value) || 'Choose a spacing preset', }, ], } ``` ## Keep the value simple Even when the UI is custom, the stored value should usually stay simple. Good examples: - a string preset - a small object - a number That makes the brick easier to render, validate, and migrate later. ## Use custom controls sparingly Custom controls are powerful, but they also create a larger maintenance surface. Try to keep them: - focused on one editing task - visually clear for editors - consistent with your design system If the control becomes too large or too application-specific, it may be a sign that the value belongs somewhere else in the app workflow. ## Summary Custom controls are the advanced extension point for `sideEditProps`. Use them when you need a better editing experience than the built-in controls can offer, but still want the value to flow through normal brick props.