Core Concepts
Mapper
How the FormWireMapper bridges form logic to UI components
The mapper is the core rendering abstraction. It maps each field kind to a React component, decoupling form logic from visual presentation.
FormWireMapper Type
type FormWireMapper = {
string: ComponentType<StringFieldProps>; // text inputs
boolean?: ComponentType<BooleanFieldProps>; // checkboxes
select?: ComponentType<SelectFieldProps>; // dropdowns
file?: ComponentType<FileFieldProps>; // file inputs
field?: ComponentType<FieldWrapperProps>; // label + input + error wrapper
group?: ComponentType<GroupProps>; // fieldset grouping
submit?: ComponentType<SubmitProps>; // submit button
status?: ComponentType<StatusProps>; // loading state
message?: ComponentType<MessageProps>; // success/error messages
};Only string is required. Everything else falls back to native HTML elements.
Using a Mapper
Wrap your app (or a subtree) with FormWireProvider:
import { FormWireProvider, htmlMapper } from "@form-wire/react";
<FormWireProvider mapper={htmlMapper}>
<MyForm />
</FormWireProvider>You can also pass a mapper per-form:
<Contact.Form action={submit} mapper={customMapper} />Per-form mapper overrides the provider mapper.
Built-in Mappers
htmlMapper
Unstyled semantic HTML. Good for testing and simple forms.
import { htmlMapper } from "@form-wire/react";
// or
import { htmlMapper } from "@form-wire/html";createShadcnMapper
Bridges shadcn/ui components. See shadcn/ui integration.
Custom Mappers
Provide functions for any subset of mapper keys:
import type { FormWireMapper, StringFieldProps, FieldWrapperProps } from "@form-wire/react";
const myMapper: FormWireMapper = {
string: ({ name, type, placeholder, required, className }: StringFieldProps) => (
<input
name={name}
type={type}
placeholder={placeholder}
required={required}
className={className ?? "my-input"}
/>
),
field: ({ field: formField, input, error }: FieldWrapperProps) => (
<div className="field-group">
<label>{formField.label}</label>
{input}
{error && <span className="error">{error}</span>}
</div>
),
};Mapper Context
Access the current mapper inside any form component:
import { useMapper } from "@form-wire/react";
function MyField() {
const mapper = useMapper();
// Use mapper.string, mapper.field, etc.
}