@letar/forms

URL Prefill

Auto-fill form fields from URL query parameters

Overview

useUrlPrefill extracts values from URL parameters and returns them for form initialization. Uses a whitelist for security — only listed fields are extracted.

Quick Example

import { useUrlPrefill } from '@letar/forms'

// URL: /contact?name=Ivan&email=ivan@test.com&hack=evil
const prefilled = useUrlPrefill({
  fields: ['name', 'email'],
  cleanUrl: true,
})
// prefilled = { name: 'Ivan', email: 'ivan@test.com' }
// 'hack' is ignored — not in whitelist

With Form

function ContactForm() {
  const prefilled = useUrlPrefill({
    fields: ['name', 'email', 'phone'],
    cleanUrl: true,
  })

  return (
    <Form schema={ContactSchema} initialValue={{ name: '', email: '', phone: '', ...prefilled }} onSubmit={save}>
      <Form.Field.String name="name" />
      <Form.Field.String name="email" />
      <Form.Field.Phone name="phone" />
      <Form.Button.Submit>Send</Form.Button.Submit>
    </Form>
  )
}

Parameter Mapping

Map URL parameter names to form field names:

// URL: /form?user_name=Ivan&mail=ivan@test.com
const prefilled = useUrlPrefill({
  fields: ['name', 'email'],
  mapping: { user_name: 'name', mail: 'email' },
})
// prefilled = { name: 'Ivan', email: 'ivan@test.com' }

Arrays and Nested Objects

// Arrays: /form?tag=react&tag=forms
// → { tag: ['react', 'forms'] }

// Nested: /form?address.city=Moscow&address.street=Tverskaya
// → { address: { city: 'Moscow', street: 'Tverskaya' } }
import { generatePrefillUrl } from '@letar/forms'

const url = generatePrefillUrl('/contact', {
  name: 'Ivan',
  email: 'ivan@test.com',
  tags: ['react', 'forms'],
})
// → "/contact?name=Ivan&email=ivan%40test.com&tags=react&tags=forms"

Props

PropTypeDefaultDescription
fieldsstring[]requiredWhitelist of allowed field names
mappingRecord<string, string>—URL param → field name mapping
cleanUrlbooleanfalseRemove params from URL after extraction
schemaZodSchema—Validate extracted values
searchParamsURLSearchParamsautoCustom source (default: window.location)

When reading from window.location, the first render (server and hydration) returns {} and the URL values appear right after mount, so the client tree matches the server markup. With an explicit searchParams the values are computed synchronously.


Live Example

Try the interactive example on forms-example.letar.best.

On this page