Custom components
For anyone who needs a component that doesn't exist in the prebuilt palette. You'll have a React component that lives in your funnel and behaves like any other Zellify block. You need familiarity with React + TypeScript, or an AI that does.
What a custom component is#
A custom component is a React + TypeScript component that you (or your AI) write inside the Zellify Component Editor. Once saved, it appears in the funnel builder's palette and your team can drag it onto any page like a prebuilt component.
The runtime injects everything the component needs: a hook-based prop API so non-developers can edit text, colors, options, and layout from the visual props panel; access to the funnel's global design tokens; navigation via useFunnelRouter(); and tracking via the tracker object. Your component reads these and renders normal JSX.
Why custom components are written a specific way#
Custom components do not work like generic React components dropped into a Next.js app. The runtime expects:
- Props are declared via Zellify hooks, not via React
props.props.useText("headerText", { default: "..." })registers an editable text field that shows up in the props panel. - A
PropEditorLayoutstatic that lays out the props panel:MyComponent.PropEditorLayout = ({ Section, Separator, Control, Label }) => ... - A
variantsstatic listing the supported variants:MyComponent.variants = [{ label: "Default", props: { _variant: "default" }, variables: {} }] - The root element must be
w-full max-w-[450px] mx-autoso the component fits the mobile viewport. - Colors come from the funnel's global color system via
useColorwithglobalColorKey. Hardcoding#000000ortext-blackproduces a component that doesn't adapt across funnels. - Bundled imports are limited to
@props,@global,@primitives,react-hook-form(for inputs), and@/lib/utils. To use an external library (Rive, Lottie, GSAP, etc.) inject a<script>tag at runtime — load it from a CDN like unpkg, then read the global the script attaches towindow.
Get any of these wrong and the component either fails to register, won't show controls in the props panel, or renders broken in the live funnel.
Two ways to build one#
1. In the Zellify Component Editor#
The Component Editor in the dashboard ships with an AI assistant that has the system prompt and props reference pre-loaded. Open the editor, describe what you want, and the AI generates a working component. This is the easiest path.
See Custom success-page component for an example walkthrough that uses funnel hooks (useVariable, tracker, useFunnelRouter).
2. With your own AI (Cursor, Claude, ChatGPT, Gemini)#
If you want to use your own AI tool — Cursor, Claude Code, Claude.ai, ChatGPT, Gemini, anything — you need to give it the same context our internal AI uses. We publish two files for this:
| File | What's in it | Raw URL |
|---|---|---|
| System prompt | Rules, conventions, structure, design system, "things that will break" | system-prompt.md |
| Props reference | Every prop hook (useText, useColor, useOptions, etc.) with full TypeScript signatures and examples | props-reference.md |
Both files are published as plain markdown so you can curl them, attach them to a Cursor .cursorrules file, paste them into a Claude Project, or feed them to any other tool.
Workflow
-
Fetch both files. From your terminal:
Or open them in a browser and copy the text.
-
Give them to your AI as context. The exact mechanism depends on your tool:
- Cursor: drop both files in a
.cursor/rules/folder, or attach them to your prompt with@. - Claude Projects: upload both as project knowledge.
- ChatGPT: paste the system prompt as a custom instruction; attach the props reference as a file.
- Claude Code / CLI: include both file paths in your prompt.
- Cursor: drop both files in a
-
Describe the component you want. Examples that work:
- "Build a testimonial card with a 5-star rating, a quote, a customer name, and a circular avatar."
- "Make a quiz component with 4 image-based options that auto-advances when an option is tapped."
- "Build a countdown timer that shows days, hours, minutes, seconds — with editable end date and labels."
-
Paste the output into the Zellify Component Editor. Open the editor, create a new component, paste the generated code, save. The editor type-checks the code and shows the live preview.
-
Iterate. If something looks off, paste the rendered preview screenshot back to your AI along with the current code and describe the change.
Common pitfalls#
| Pitfall | Why it happens | Fix |
|---|---|---|
| Props panel shows nothing | Forgot to declare props with props.use* hooks | Every editable field must be a hook call |
| Colors don't change with the funnel | Hardcoded hex or Tailwind color class | Use props.useColor with globalColorKey |
| Component doesn't fit the page | Missing w-full max-w-[450px] mx-auto on the root | Add it to the outermost div |
| Form input doesn't submit | Forgot useFormContext + Controller from react-hook-form | Wire form inputs through React Hook Form |
| Auto-navigation breaks on tab background | Used requestAnimationFrame for timers | Use setTimeout with absolute offsets |
| Variant switcher missing | No variants static array | Add at minimum a default variant |