shadcn/ui component
Install a form component that renders your Ikiform fields with your own shadcn/ui components.
If your project uses shadcn/ui, you can install a ready-made form instead of writing the markup. It is one option among several: the same form keeps working with plain HTML and fetch.
Install
npx shadcn@latest add https://ikiform.com/r/form.jsonThis copies components/ikiform/form.tsx into your project and installs the shadcn/ui components it uses: button, checkbox, input, label, radio-group and textarea. The file is yours to edit. Selects use a native <select>, so it works with both the Radix and Base UI flavours of shadcn/ui.
Usage
import { IkiForm } from "@/components/ikiform/form";
export default function Contact() {
return <IkiForm form="frm_xxxxxxxxxxxxxxxx" />;
}On mount the component fetches the form's public schema and renders one control per field, using the labels, placeholders, help text and options you set in the dashboard. Define fields first on the Fields tab of the form; a form without fields renders no inputs.
- It validates in the browser with the same rules and messages as the server.
- It posts JSON with the honeypot and a signed render timestamp, which helps spam scoring.
- Server field errors appear under their fields; other errors appear above the button.
- On success it replaces the form with the form's success message.
Props
| Prop | Type | Description |
|---|---|---|
form | string | Required. The form id. |
fields | IkiFormField[] | Replaces the fetched fields. Uses the same shape as field definitions. |
onSuccess | ({ id, values }) => void | Called after a successful submit. |
submitLabel | string | Button text. Defaults to the form's submit label. |
successMessage | ReactNode | Shown after submit. Defaults to the form's success message. |
turnstileSiteKey | string | Only for forms with your own Turnstile keys and no site key saved in Ikiform. |
className | string | Class names for the form element. |
baseUrl | string | Defaults to https://ikiform.com. |
import { IkiForm } from "@/components/ikiform/form";
export default function Waitlist() {
return (
<IkiForm
form="frm_xxxxxxxxxxxxxxxx"
submitLabel="Join the waitlist"
successMessage="You're on the list."
onSuccess={({ id }) => console.log("Submitted", id)}
/>
);
}Fields in code
Pass fields to render without the dashboard definition. The server still validates against the form's published fields, so keep the two in sync.
<IkiForm
form="frm_xxxxxxxxxxxxxxxx"
fields={[
{ id: "email", type: "email", label: "Work email", required: true },
{ id: "team_size", type: "number", label: "Team size", validation: { min: 1, integer: true } },
]}
/>Human check
With the spam check set to Ikiform, the component embeds a small ikiform.com frame that stays hidden until Turnstile needs a click, and asks for a fresh token after every attempt. If the frame can't load, it offers to open the check in a new window. With your own Turnstile keys, it renders the Turnstile widget with the form's site key.
The schema endpoint
The component reads GET https://ikiform.com/f/<formId>/schema. You can call it yourself to build your own renderer, or use getSchema from the SDK.
{
"id": "frm_xxxxxxxxxxxxxxxx",
"title": "Contact",
"description": null,
"fields": [{ "id": "email", "type": "email", "label": "Email", "required": true }],
"settings": { "submit_label": "Send", "success_message": "Thanks!" },
"honeypot_field": "_gotcha",
"turnstile_required": false,
"turnstile_site_key": null,
"challenge": null,
"ts": "1792300000000.signature"
}- Open to any origin (
Access-Control-Allow-Origin: *) and never cached. - Paused, disabled and unknown forms all return the same
404. - Only the published fields and display settings leave the server. Allowed domains, the redirect URL, spam settings and rate limits stay private.
challengeis{ "provider": "ikiform", "url": ... },{ "provider": "custom", "site_key": ... }ornull.tsis a fresh signed render timestamp to send back as_ikiform_ts.- It allows 60 requests a minute per visitor and form, separate from the submit allowance.