@robinpath/react
v0.1.1
Published
RobinPath React components — render forms from RobinPath schemas
Downloads
9
Readme
@robinpath/react
Enterprise-grade React form renderer for RobinPath schemas. Render dynamic forms from JSON — works with React 18+, Next.js, Remix, Gatsby, Astro, and any React environment.
Install
npm install @robinpath/reactQuick Start
From a schema (local)
import { FormRenderer } from '@robinpath/react';
import type { FormSchema } from '@robinpath/react';
const schema: FormSchema = {
config: { title: 'Contact Us', submitLabel: 'Send' },
fields: [
{ name: 'name', type: 'text', label: 'Name', required: true, order: 0 },
{ name: 'email', type: 'email', label: 'Email', required: true, order: 1 },
{ name: 'message', type: 'textarea', label: 'Message', order: 2 },
],
};
function App() {
return (
<FormRenderer
schema={schema}
onSubmit={(values) => console.log(values)}
theme="dark"
/>
);
}From CDN (RobinPath snippet)
import { RobinPathForm } from '@robinpath/react';
function App() {
return (
<RobinPathForm
snippetId="your-snippet-id"
onSubmit={(values) => console.log(values)}
onResult={(result) => console.log(result)}
/>
);
}Programmatic Control
Access the form imperatively via ref:
import { useRef } from 'react';
import { FormRenderer } from '@robinpath/react';
import type { FormHandle } from '@robinpath/react';
function App() {
const formRef = useRef<FormHandle>(null);
return (
<>
<FormRenderer ref={formRef} schema={schema} onSubmit={handleSubmit} />
<button onClick={() => formRef.current?.submit()}>Submit Externally</button>
<button onClick={() => formRef.current?.reset()}>Reset</button>
<button onClick={() => formRef.current?.setValue('name', 'John')}>Set Name</button>
</>
);
}FormHandle API
| Method | Description |
|--------|-------------|
| submit() | Submit the form programmatically |
| reset() | Reset to initial values |
| validate() | Validate all fields, returns ValidationError[] |
| getValues() | Get current form values |
| setValue(name, value) | Set a single field value |
| setValues(values) | Set multiple values |
| setError(name, message) | Set a field error |
| clearErrors() | Clear all errors |
| focus(name) | Focus a specific field |
| getState() | Get full form state |
Props
FormRenderer
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| schema | FormSchema | required | Form schema from RobinPath |
| initialValues | FormValues | — | Override default values |
| onChange | (values, fieldName) => void | — | Called on every field change |
| onSubmit | (values) => void \| Promise | — | Called on valid submit |
| onValidationError | (errors) => void | — | Called when validation fails |
| onBlur | (fieldName, value) => void | — | Called on field blur |
| theme | 'dark' \| 'light' | 'dark' | Theme preset |
| className | string | — | Root element class |
| style | CSSProperties | — | Root element styles |
| disabled | boolean | false | Disable all fields |
| hideSubmit | boolean | false | Hide submit button |
| submitLabel | string | 'Submit' | Custom submit text |
| showBranding | boolean | false | Show RobinPath footer |
| validateOnBlur | boolean | true | Validate on blur |
| validateOnChange | boolean | false | Validate on change |
| focusOnError | boolean | true | Focus first error on submit |
| renderField | (field, props) => ReactNode | — | Custom field renderer |
| renderSubmit | (props) => ReactNode | — | Custom submit button |
| idPrefix | string | 'rp' | ID prefix for SSR |
RobinPathForm
Extends all FormRenderer props, plus:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| snippetId | string | required | RobinPath snippet ID |
| cdnUrl | string | 'https://cdn.robinpath.com' | CDN base URL |
| executeOnSubmit | boolean | true | Execute script on CDN |
| onResult | (result) => void | — | Execution result callback |
| renderLoading | () => ReactNode | — | Custom loading UI |
| renderError | (error) => ReactNode | — | Custom error UI |
Field Types
All 19 field types supported:
text · textarea · password · email · url · phone · number · range · select · multiselect · radio · checkbox · date · time · datetime · file · hidden · color · json
Custom Field Renderer
<FormRenderer
schema={schema}
renderField={(field, props) => (
<div key={field.name}>
<label>{field.label}</label>
<input
value={String(props.value ?? '')}
onChange={(e) => props.onChange(e.target.value)}
onBlur={props.onBlur}
/>
{props.error && props.touched && <span>{props.error}</span>}
</div>
)}
onSubmit={handleSubmit}
/>Conditional Fields
Fields can be conditionally visible based on other field values:
const schema: FormSchema = {
config: {},
fields: [
{ name: 'hasCompany', type: 'checkbox', label: 'I have a company', order: 0 },
{ name: 'company', type: 'text', label: 'Company Name', order: 1, showWhen: 'hasCompany' },
{ name: 'role', type: 'select', label: 'Role', order: 2, options: [
{ value: 'dev', label: 'Developer' },
{ value: 'manager', label: 'Manager' },
]},
{ name: 'team_size', type: 'number', label: 'Team Size', order: 3, showWhen: 'role', showWhenValue: 'manager' },
],
};Context Hook
Access form state from nested components:
import { useFormContext } from '@robinpath/react';
function StatusBar() {
const { values, errors, isSubmitting } = useFormContext();
return <div>Fields filled: {Object.values(values).filter(Boolean).length}</div>;
}Accessibility
WCAG 2.1 AA compliant:
aria-invalidon error fieldsaria-describedbylinking errors and descriptionsaria-requiredon required fieldsrole="alert"on error messagesrole="radiogroup"on radio groupsaria-live="polite"on success state- Keyboard navigable
- Auto-focus first error on submit
Architecture
useSyncExternalStore— React 18+ concurrent mode safe, no tearingmemofield renderer — only rerenders when own value/error/touched changes- Error boundary — graceful crash recovery
- Zero CSS dependencies — inline styles via CSS variables
- 29KB bundle — tree-shakeable ES module
License
MIT
