When a Fillo form misbehaves.
The five failure modes we actually see — symptom, cause, fix — plus the JSX authoring error catalog. Ninety seconds, tops.
Setup lives at /docs/embed, the styling contract at /docs/styling.
On this page
The form renders unstyled under Tailwind v3
- Symptom
- The form works but looks bare — no borders, spacing, or button styling.
- Cause
@usefillo/react/styles.cssships its rules in@layer components. Any unlayered CSS — Tailwind v3’s preflight, most resets — outranks every layered rule, so the default theme silently evaporates.- Fix
- Import
@usefillo/react/styles.unlayered.cssinstead. Details in the stylesheet matrix.
The hosted /f page doesn't match my embed
- Symptom
appearance.classNamesstyling shows in your app but not on the hosted page or dashboard preview.- Cause
- By design — classNames never sync; the hosted page renders the default renderer plus theme tokens only.
- Fix
- Put brand parity in theme tokens (
defineForm({ theme })or the dashboard theme); keep classNames for embed-only polish.
The form says “This form isn’t live yet” or eats submissions
- Symptom
- A code-defined form renders, but shows “This form isn’t live yet” in production (or a draft banner in dev) and refuses responses.
- Cause
- Code forms sync as drafts; the server rejects public submissions until a human publishes.
- Fix
- Publish the form in the dashboard — the browser console notice links straight to it. Staged schema changes need the same publish step.
Submit fails with “Couldn’t reach the server”
- Symptom
- The form fails to load or submit with a network error while the rest of the site is fine.
- Cause
- An ad-blocker, corporate firewall, or your site's Content-Security-Policy is blocking requests to fillo.so.
- Fix
- Check the browser network tab for the blocked request. If your site sets a CSP, allow
connect-src https://fillo.so. For ad-blockers and VPNs, retry with them off to confirm.
Blank form, or “useFillo must be used inside…”
- Symptom
- The form renders nothing, or a component that is clearly inside the provider throws
useFillo must be used inside <FilloForm> or <FilloProvider>. - Cause
- Two copies of
@usefillo/react(or of React itself) in the bundle — context identity differs across copies. - Fix
- Dedupe to a single copy:
npm dedupe/ one version in the lockfile; in monorepos check hoisting and bundler aliases.
JSX authoring errors
Mistakes in <Fillo.Form> authoring throw FilloJsxError with a stable code; the error message links straight to its entry below. The authoring guide lives at /docs/authoring.
jsx-missing_id
A block, an <Fillo.Option>, or <Fillo.Form> itself has no stable string id (1–128 chars); options also need a label.
Fix: Write a permanent id by hand — ids key responses, logic, piping, and sync, so never derive them from position or a counter.
jsx-duplicate_id
Two blocks share one id. Ids key responses and must be unique across the whole form, pages included.
Fix: Rename one. If the form is live, keep the id existing responses were stored under and rename the newcomer.
jsx-non_fillo_child
Something that isn't a Fillo element sits where the schema expects one — raw text or HTML inside <Fillo.Form>, children on a props-only field, or <Fillo.Option> outside a choice field.
Fix: Children define the schema: put text in <Fillo.Paragraph>, layout outside the form (or go headless with FilloProvider), and options inside Select, MultiSelect, Dropdown, or Ranking.
jsx-wrapper_component
A plain React component was used as a form child. The compiler never renders children, so wrappers are invisible to it.
Fix: Reuse via a plain function that returns Fillo elements and call it inline: {contactFields()}.
jsx-opaque_type
A child's component type is opaque — lazy/memo, or the JSX crossed a server-component boundary and arrived as a reference.
Fix: Define the form in a client module ("use client") and pass the compiled value across server/client boundaries, never the JSX.
jsx-unknown_prop
A prop isn't in that component's schema whitelist. Typos and className/style land here instead of vanishing silently.
Fix: Use the props in the component reference; styling lives on <Fillo.Form appearance={…}>, never in the schema.
jsx-option_prop_conflict
A choice field has both an options prop and <Fillo.Option> children, or a heading/paragraph has both a text prop and children.
Fix: Pick one source — both compile identically.
jsx-page_mix
<Fillo.Form> mixes <Fillo.Page> elements with loose blocks, or a Page/Option appears inside a page.
Fix: Children are either all pages or all blocks — wrap the loose blocks in a <Fillo.Page>.
jsx-text_child_required
A Heading or Paragraph has non-string children (expressions, elements), or no text at all.
Fix: Pass plain text as children or the text prop — piping tokens like {{name}} are fine.
jsx-rendered_inert
React actually rendered a Fillo.* field — it was used outside <Fillo.Form> / Fillo.defineForm(), often from a server component.
Fix: Keep fields inside <Fillo.Form>, and define the form in a client module ("use client").