Skip to content

Custom Fields

Rebase generates form fields automatically based on property types. For custom behavior, you can build your own fields.

A custom field is a React component that receives FieldProps:

import { FieldProps } from "@rebasepro/core";
function ColorPickerField({ value, setValue, error, showError }: FieldProps<string>) {
return (
<div>
<input
type="color"
value={value ?? "#000000"}
onChange={(e) => setValue(e.target.value)}
/>
{showError && error && <span className="text-red-500">{error}</span>}
</div>
);
}
PropTypeDescription
valueTCurrent field value
setValue(value: T) => voidUpdate the field value
errorstringValidation error message
showErrorbooleanWhether to display the error
isSubmittingbooleanForm is being saved
propertyPropertyThe property configuration
contextFormContextFull form context with all entity values
disabledbooleanField is readonly
tableModebooleanRendering inside the spreadsheet (compact mode)

Register on a single property:

properties: {
brand_color: {
type: "string",
name: "Brand Color",
Field: ColorPickerField
}
}

Register a reusable field type:

const colorPropertyConfig: PropertyConfig = {
key: "color_picker",
name: "Color Picker",
Field: ColorPickerField,
property: {
type: "string"
}
};
// Register globally
<Rebase propertyConfigs={[colorPropertyConfig]} ... />

Then use it in any collection:

properties: {
color: {
type: "string",
name: "Color",
propertyConfig: "color_picker"
}
}

Custom fields can access the full entity values:

function PriceWithTaxField({ value, setValue, context }: FieldProps<number>) {
const taxRate = context.values.tax_rate ?? 0.1;
const priceWithTax = value ? value * (1 + taxRate) : 0;
return (
<div>
<input
type="number"
value={value ?? 0}
onChange={(e) => setValue(Number(e.target.value))}
/>
<p>With tax: ${priceWithTax.toFixed(2)}</p>
</div>
);
}

When rendering inside the spreadsheet view, fields should be compact. Check tableMode:

function MyField({ value, setValue, tableMode }: FieldProps<string>) {
if (tableMode) {
return <span onClick={() => { /* open editor */ }}>{value}</span>;
}
return (
<div>
<label>Full Editor</label>
<textarea value={value ?? ""} onChange={(e) => setValue(e.target.value)} />
</div>
);
}

For custom rendering in the table (non-editing mode), use the Preview component:

function ColorPreview({ value }: { value: string }) {
return (
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<div style={{
width: 24, height: 24,
borderRadius: 4,
backgroundColor: value
}} />
<span>{value}</span>
</div>
);
}
// Register it
properties: {
color: {
type: "string",
name: "Color",
Field: ColorPickerField,
Preview: ColorPreview
}
}