The Fillo API, on one page.
Every prop, hook, client method, settings key, theme token, and renderer string in @usefillo/react, @usefillo/core, and @usefillo/dom. The token and string tables render from the SDK’s own exports, so they can’t drift.
Task-shaped docs: install at /docs/embed, JSX authoring at /docs/authoring, slots and data-* attributes at /docs/styling.
On this page
<FilloForm>
The framed renderer. Pass formId (a published, dashboard-hosted form) or form (a schema or a code-defined form); code forms need client to save responses.
| Prop | Type | What it does |
|---|---|---|
| formId | string | Fetch a published form by id or slug. With only this prop, a default client (→ fillo.so) is created. |
| form | FormSchema | CodeForm | Render a schema directly, or a defineForm() / Fillo.defineForm() form — which also syncs. |
| client | FilloClient | From createClient(). Required for code-defined forms that should save responses. |
| theme | FormTheme | Theme tokens. Precedence: appearance.theme, then this prop, then the code form's theme, then the dashboard theme. |
| appearance | FilloAppearance | The styling contract: theme + per-slot classNames + per-field overrides. See /docs/styling. |
| strings | Partial<FilloStrings> | Override any visitor-facing renderer string (localized sites). |
| components | FieldComponents | Swap any built-in field kind for your own component. |
| customComponents | CustomComponents | Renderers for your own `custom` field kinds, keyed by the field's `component`. |
| initialData | ResponseData | Pre-filled answers, keyed by field id. |
| onChange | (data: ResponseData) => void | Fires with the full answer map on every edit. |
| onSubmitted | (responseId: string | undefined, data: ResponseData) => void | Runs after Fillo records the response. |
| onError | (error: FilloError) => void | Observe load and code-form sync failures (otherwise only logged). |
| showTitle | boolean (default true) | Render the form's own title/description header. Set false when the page already has the heading. |
| renderSuccess | () => ReactNode | Custom success screen. |
| renderError | (error: FilloError) => ReactNode | Custom error screen — receives the failure (e.g. 404 vs network). |
| className | string | Extra classes on the root element. |
<FilloProvider> + <FormField>
The headless escape hatch: runs the same engine, renders no layout. Compose your own with <FormField>, useField(), and useFillo()— render every required field, or submission fails on a field the visitor can’t see.
| Prop | Type | What it does |
|---|---|---|
| form | FormSchema | CodeForm (required) | The schema to run. A defineForm() form also syncs, exactly like <FilloForm>. |
| client | FilloClient | Submission (and sync) target. |
| formId | string | Explicit submission target for a plain schema. |
| appearance | FilloAppearance | Slot classes for FormField-rendered fields. |
| strings | Partial<FilloStrings> | Renderer string overrides. |
| initialData | ResponseData | Pre-filled answers. |
| onChange / onSubmitted | as on <FilloForm> | Same callbacks, same timing. |
| children | ReactNode | Your layout — fields go wherever you render them. |
<FormField> renders one field with the default (or overridden) component, in your layout:
| Prop | Type | What it does |
|---|---|---|
| id | string (required) | Which field to render. Returns null for unknown ids and for fields hidden by conditional logic. |
| components | FieldComponents | Per-kind overrides, scoped to this one field. |
| customComponents | CustomComponents | Custom-kind renderers, scoped to this one field. |
<Fillo.Form> extras
The JSX authoring root (guide: /docs/authoring). Besides every <FilloForm> prop above (except form/formId), it takes the schema-level props:
| Prop | Type | What it does |
|---|---|---|
| id | string (required) | Workspace handle — the form's identity across syncs. |
| title / description | string | Form header copy, compiled into the schema. |
| settings | FormSettings | The settings.* keys below, compiled into the schema. |
| theme | FormTheme | Theme tokens, compiled into the CodeForm (they sync to the hosted page). |
| client | FilloClient | Sync + submission target. |
| children | Fillo.* elements | The schema: pages or blocks. Never rendered — compiled. |
Hooks
useFillo() returns the full engine API — it throws outside <FilloForm> / <FilloProvider>:
| Member | Type | What it is |
|---|---|---|
| form | FormSchema | The normalized schema being rendered. |
| formId | string | undefined | Submission target, once known (code forms resolve it after sync). |
| client | FilloClient | undefined | The client in use. |
| data | ResponseData | Current answers, keyed by field id. |
| errors | Record<string, string> | Validation messages, keyed by field id. |
| setValue | (fieldId, value) => void | Write an answer. Clears that field's error; re-checked on next/submit. |
| pageIndex / pageCount | number | Current page (0-based) and total pages. |
| page | FormPage | The current page. |
| blocks | Block[] | The current page's blocks after conditional-visibility logic. |
| isFirstPage / isLastPage | boolean | Position flags for your own footer. |
| next() / back() | () => void | Page navigation. next() validates the current page first and stays put on errors. |
| submit() | () => Promise<void> | Validates everything, submits, and settles state. Rejections also land in submitError. |
| status | "idle" | "submitting" | "submitted" | "error" | Engine status (also on the root as data-state). |
| uploading | boolean | True while any file upload is in flight — submit is blocked. |
| submitError | string | undefined | Message of the last failed submit; cleared on edit/retry. |
| setUploading | (fieldId, busy) => void | Used by upload fields to gate submission. |
useField(id) drives one field — the lowest-level hook:
| Member | Type | What it is |
|---|---|---|
| field | Field | undefined | The field's schema entry, or undefined if no field has this id. |
| value | FieldValue | The current answer. |
| error | string | undefined | The current validation message. |
| setValue | (value: FieldValue) => void | Write the answer. |
useFilloController(options) is the React binding both components use — same options as <FilloProvider>. Outside React, the identical engine is createFormController() from @usefillo/core or @usefillo/dom.
import { FilloProvider, FormField, useField, useFillo } from "@usefillo/react";
function SubmitBar() {
const { isLastPage, next, submit, status } = useFillo();
return (
<button onClick={() => (isLastPage ? void submit() : next())}>
{status === "submitting" ? "Sending…" : isLastPage ? "Send" : "Next"}
</button>
);
}
function BareEmail() {
const { value, error, setValue } = useField("email");
return <input value={String(value ?? "")} onChange={(e) => setValue(e.target.value)} aria-invalid={!!error} />;
}createClient
import { createClient } from "@usefillo/react"; // or "@usefillo/dom"
const client = createClient({
key: process.env.NEXT_PUBLIC_FILLO_KEY!, // pk_… — public by design
});| Option | Type | What it does |
|---|---|---|
| key | string | Publishable workspace key (pk_…) — safe to ship in client code. Required only for syncing code-defined forms. |
| baseUrl | string | Target a different Fillo server (staging, tests, a proxy on your own domain). Wins over sameOrigin. |
| sameOrigin | boolean | Internal: Fillo's own first-party pages only. Not for embedding. |
| fetch | typeof fetch | Custom fetch implementation. |
Methods — requests time out after 30 seconds; failures throw FilloError with status and, on 429, retryAfterSec:
| Method | Returns | What it does |
|---|---|---|
| getForm(idOrSlug) | Promise<PublishedForm> | Fetch a published form: { id, slug, schema, theme, closed?, branding? }. |
| submit(formId, data, meta?) | Promise<SubmitResult> | Record a response. Validation failure returns { ok: false, errors } (per field) instead of throwing. |
| syncForm(handle, schema, theme?) | Promise<SyncFormResult> | Upsert a code-defined form into the workspace. Needs `key`; returns the canonical formId and lifecycle status. |
| uploadFile(formId, file, { fieldId, onProgress?, signal?, sessionId?, uploadToken? }) | Promise<FileValue> | Resumable chunked upload straight to the form's storage; the FileValue goes into response data. |
settings.* keys
On defineForm({ settings }), <Fillo.Form settings={…}>, or the dashboard. All optional.
| Key | Type | What it does |
|---|---|---|
| submitMode | "button" | "auto" | Default "button". "auto" submits after a single discrete answer and hides the final submit button — one-tap votes, CSAT, NPS. |
| submitLabel | string | Custom submit button text. |
| successTitle | string | Thank-you screen title (wins over the strings default). |
| successMessage | string | Thank-you screen body (wins over the strings default). |
| redirectUrl | string | Redirect after submit instead of the success screen. http(s) only. |
| showProgress | boolean | Progress bar on multi-page forms (default true). |
| submissionLimit | "multiple" | "once_per_visitor" | Default "multiple". once_per_visitor remembers this browser answered and sends a server-side de-duplication key. |
| notifyEmail | string | Notify this address on every submission. |
| sendReceipt | boolean | Email respondents a receipt (to the first answered email field). |
Theme tokens
Generated from FILLO_THEME_VARS (exported by @usefillo/core). Tokens with a FormTheme key are set inline by the theme prop / defineForm({ theme }) and sync to the hosted page; the rest are stylesheet-only — override them from your CSS on any ancestor. FormTheme.colorScheme is not a variable: it sets data-fillo-color-scheme on the root.
| CSS variable | FormTheme key | What it paints |
|---|---|---|
| --fillo-primary | primary | Buttons, focus rings, selection. |
| --fillo-bg | background | Form background. |
| --fillo-text | text | Body text. |
| --fillo-radius | radius | Corner radius scale. |
| --fillo-font | fontFamily | Font family. |
| --fillo-muted | stylesheet-only | Descriptions, hints, placeholders. |
| --fillo-border | stylesheet-only | Input borders, dividers. |
| --fillo-control-bg | stylesheet-only | Input backgrounds. |
| --fillo-error | stylesheet-only | Validation messages. |
| --fillo-primary-contrast | stylesheet-only | Text on primary buttons. |
Strings
Generated from DEFAULT_STRINGS (exported by @usefillo/core). Override any subset via the strings prop; schema-authored text — labels, success copy in settings — always wins.
| Key | Default | Shown |
|---|---|---|
| back | Back | Back button on multi-page forms. |
| next | Next | Next button between pages. |
| submit | Submit | Submit button on the last page (settings.submitLabel wins). |
| submitting | Submitting… | Submit button while the request is in flight. |
| uploading | Uploading… | Submit button while a file upload is in flight. |
| optional | (optional) | Suffix on non-required field labels. |
| other | Other | The "Other" free-text choice row. |
| otherPrompt | Other — please specify | The "Other" dropdown entry prompt. |
| otherPlaceholder | Your answer | Placeholder of the "Other" free-text input. |
| choosePlaceholder | Choose… | Dropdown placeholder when the field sets none. |
| successTitle | Thanks! | Success screen title (settings.successTitle wins). |
| successMessage | Your response has been recorded. | Success screen body (settings.successMessage wins). |
| closed | This form is no longer accepting responses. | The form is no longer accepting responses. |
| notLive | This form isn't live yet. | An unpublished code form, in production. |
| submitFailed | This form can't submit right now. Please try again in a moment. | Fallback when a submit fails without a server message. |
| loadFailedNotFound | Form not found — check the form id and that it's published. | A hosted form id/slug that doesn't resolve (404). |
| loadFailedNetwork | Couldn't reach the server — check your connection or CORS. | The load request never reached the server. |
| loadFailed | This form could not be loaded. | Any other load failure. |
| renderFailed | This form could not be rendered. | The schema failed validation and can't render. |
@usefillo/dom
renderForm(target, options) — target is an element or a selector string; returns a handle.
import { renderForm } from "@usefillo/dom";
import "@usefillo/dom/styles.css";
const instance = renderForm("#form", {
formId: "customer-onboarding",
onSubmitted: (id, data) => console.log("response", id, data),
});
// instance.setValue("email", "jane@example.com");
// await instance.submit();
// instance.destroy();| Option | Type | What it does |
|---|---|---|
| form | FormSchema | CodeForm | Render a schema or a defineForm() form (which also syncs). |
| formId | string | Fetch a published form by id or slug (a default client is created if none is passed). |
| client | FilloClient | Submission (and sync) target. |
| theme | FormTheme | Theme tokens applied to the root. |
| initialData | ResponseData | Pre-filled answers. |
| className | string | Extra classes on the rendered form. |
| components | Partial<Record<FieldKind, FieldRenderer>> | Swap any built-in field kind; a FieldRenderer returns an HTMLElement. |
| customComponents | Record<string, FieldRenderer> | Renderers for your own `custom` field kinds. |
| onChange / onSubmitted / onError | as on <FilloForm> | Same callbacks, same timing. |
| renderSuccess | (api: FilloDomApi) => HTMLElement | Custom success screen. |
| renderError | (error: FilloError) => HTMLElement | Custom error screen. |
The returned handle:
| Member | Type | What it is |
|---|---|---|
| element | HTMLElement | The rendered root. |
| status | FormStatus | "loading" | "closed" | Engine status, plus the wrapper-only fetching/closed states. |
| data | ResponseData | Current answers. |
| form | FormSchema | null | The resolved schema (null while loading). |
| setValue(fieldId, value) | void | Write an answer programmatically. |
| next() / back() | void | Page navigation (next validates first). |
| submit() | Promise<void> | Validate and submit. |
| destroy() | void | Tear down the DOM and every listener. |
Also exported: createFormElement(options) (build a detached node), the <fillo-form> web component (registerFilloElement(); publishable-key / form-id attributes, fillo-change / fillo-submit / fillo-error events), and createFormController() — the render-nothing engine for Vue, Svelte, or vanilla layouts.