Form Wire
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.
}

On this page