Skip to main content

Add a form to React

Render a published or code-defined Fillo form in React as native elements, with optional default CSS and saved responses.

Build this with your agent. Copy a prompt that hands this guide to Claude Code, Codex, Cursor, or any coding agent.

Render a Fillo form as native elements in your React component tree, with no iframe. You end with a form that validates in the browser and saves responses to your Fillo project.

Render a published form

Install the package:

bash
npm install @usefillo/react

Pass the form ID or slug from the dashboard's Share panel:

tsx
import { FilloForm } from "@usefillo/react";
import "@usefillo/react/styles.css"; // optional default theme

export function FeedbackCard() {
  return (
    <section aria-labelledby="feedback-title">
      <h2 id="feedback-title">Product feedback</h2>
      <FilloForm
        formId="your-published-form-id"
        showTitle={false}
        onSubmitted={(responseId) => console.info("Fillo response", responseId)}
      />
    </section>
  );
}

A published form loads and accepts responses without a key. Hide the form title only when the page shows its own heading.

Define the form in code

Keep the schema in your repo with defineForm(). A client with your project's publishable pk_ key lets the form save responses.

tsx
import { createClient, defineForm, FilloForm } from "@usefillo/react";

const client = createClient({ key: import.meta.env.VITE_FILLO_KEY });

const feedback = defineForm({
  id: "product-feedback",
  title: "Product feedback",
  pages: [{ id: "main", blocks: [
    { id: "message", kind: "long_text", label: "What should we improve?", required: true },
    { id: "email", kind: "email", label: "Email for a reply" },
  ] }],
  settings: { submitLabel: "Send feedback" },
});

export function Feedback() {
  return <FilloForm form={feedback} client={client} />;
}

Create the client and the form at module scope, not inside the component.

In a claimed workspace, a changed schema becomes a draft. Publish it in the dashboard or with fillo publish before you rely on it. See the code-defined form lifecycle.

Why the form lives at module scope

The form's identity must not change between renders. Recreating the client or the schema on every render adds work and can hide sync errors. For a Vite app, the VITE_ prefix exposes the key to browser code. The pk_ key is publishable by design. It can't publish a live change.

Props you'll use

PropUse
formIdA published form ID or slug. No key needed.
form and clientA code-defined form that saves responses.
renderOnlyA local preview. It can't save responses or upload files.
onSubmittedRuns after Fillo records the response.
showTitleSet false when the page supplies its own heading.
theme, appearanceDesign tokens and named slot classes.
initialDataPrefill answers by field ID.
respondentSigned-in account context, hashed on your server.

Match your styles

Use theme for tokens or appearance for slot classes. Tailwind can target state attributes such as data-[invalid] and data-[selected]. See styling for the slot list.

Check it before you ship

  1. Tab through every field and the submit button.
  2. Submit empty and confirm focus moves to the first error.
  3. Submit with the network off, then retry without retyping.
  4. Check the pending state, the success state, and a narrow screen.
  5. Open Responses in Fillo and find the saved answer.

This page for agents: /guides/react-form.md · index at /llms.txt

Updated

Was this page helpful?