---
title: "Custom"
description: "Store any JSON value and render the field with your own component."
group: "Build forms"
order: 18
type: "reference"
parent: "fields"
keywords:
  - "custom"
  - "component"
  - "config"
  - "customComponents"
  - "JSON"
updated: "2026-07-14"
---

The custom field stores arbitrary JSON and delegates rendering and type-specific validation to a component you provide.

## Options

| Option | Type | Behavior |
| --- | --- | --- |
| `component` | `string` | Selects a renderer from the SDK `customComponents` map |
| `config` | `Record<string, unknown>` | Passes JSON configuration to that renderer |
| `required` | `boolean` | Lets core reject an empty value |

Core doesn't know the shape of a custom answer. It checks that a required field isn't empty, then preserves the JSON value as-is — richer validation and accessible interaction are your component's job.

Custom fields are code-only. They don't appear in the dashboard's **Add block** palette because the dashboard can't supply your host component.

## Define and render a custom field

```tsx
const form = defineForm({
  id: "delivery-area",
  pages: [{
    id: "main",
    blocks: [{
      id: "location",
      kind: "custom",
      component: "map-pin",
      label: "Drop a pin",
      required: true,
      config: { zoom: 12 },
    }],
  }],
});

<FilloForm
  form={form}
  client={client}
  customComponents={{ "map-pin": MapPinField }}
/>
```

Custom fields can't be prefilled from a URL. Use `initialData` when the component can safely accept a known initial value.

## Related

- [Custom UI](/docs/custom-ui): Implement the renderer contract and full headless layouts.
- [Schema and validation](/docs/schema): Understand what core can and can't validate.
- [Fields](/docs/fields): Use a built-in type when its value model already fits.
