Advanced

Theming

Customize the appearance of every form element — inputs, labels, errors, dropdowns, and more — through the theming system.


Default theme

The web library ships with a Tailwind CSS theme (tailwindTheme) that's applied automatically. No configuration needed.

import { Form, FormFieldClass } from '@nestledjs/forms'

// Uses tailwindTheme by default
;<Form id="my-form" fields={fields} submit={save}>
  <button type="submit">Submit</button>
</Form>

Custom themes

Create a custom theme by providing a theme object to the Form component.

import { Form, createCustomTheme } from '@nestledjs/forms'

const myTheme = createCustomTheme({
  input: 'border-2 border-indigo-300 rounded-lg px-4 py-3 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200',
  label: 'text-sm font-bold text-indigo-900 mb-2',
  error: 'text-red-600 text-xs mt-1 font-medium',
  helpText: 'text-indigo-400 text-xs mt-1',
})

<Form id="styled-form" fields={fields} submit={save} theme={myTheme}>
  <button type="submit">Submit</button>
</Form>

createCustomTheme

createCustomTheme merges your overrides with the default tailwindTheme. You only need to specify the properties you want to change.

const theme = createCustomTheme({
  input: 'custom-input-class', // Overrides input styles
  label: 'custom-label-class', // Overrides label styles
  // All other properties inherit from tailwindTheme
})

Theme properties

The theme object controls styling for every part of every field type.

Global properties

PropertyDescription
inputText input, email, password, URL, number fields
textareaTextArea field
labelField labels
errorValidation error messages
helpTextHelp text below fields
fieldWrapperWrapper around each field (label + input + error)
requiredRequired indicator styling
placeholderPlaceholder text styling

Select properties

PropertyDescription
selectStandard select dropdown
selectMultiMulti-select dropdown
selectOptionIndividual option in dropdown
selectOptionSelectedSelected option styling

Search select properties

PropertyDescription
searchInputSearch input inside dropdown
searchDropdownDropdown container
searchOptionIndividual search result option
searchOptionHighlightedHighlighted/hovered search option
inputWithClearInput wrapper when clear button is shown
clearButtonClear/X button
clearIconIcon inside clear button

Checkbox and switch properties

PropertyDescription
checkboxCheckbox input
checkboxLabelLabel next to checkbox
switchSwitch/toggle input
switchLabelLabel next to switch
customCheckboxCustom checkbox styling
radioOptionIndividual radio button
radioLabelLabel next to radio button
checkboxGroupOptionIndividual checkbox in a group
checkboxGroupLabelLabel in checkbox group

Date/time properties

PropertyDescription
datePickerDate picker input
dateTimePickerDateTime picker input
timePickerTime picker input

Other properties

PropertyDescription
buttonButton field styling
contentContent field wrapper
markdownEditorMarkdown editor container
customFieldCustom field wrapper

Full theme override

To replace the default theme entirely instead of merging:

import { Form } from '@nestledjs/forms'

const fullTheme = {
  input: 'my-input',
  textarea: 'my-textarea',
  label: 'my-label',
  error: 'my-error',
  helpText: 'my-help',
  fieldWrapper: 'my-wrapper',
  select: 'my-select',
  checkbox: 'my-checkbox',
  // ... provide all properties
}

<Form id="form" fields={fields} submit={save} theme={fullTheme}>
  <button type="submit">Submit</button>
</Form>

Theme reference

Use themeReference to see all available theme properties and their default values:

import { themeReference } from '@nestledjs/forms'

console.log(themeReference)
// Logs all theme property names and descriptions

Generate a theme template

Use generateThemeTemplate to get a starter theme object:

import { generateThemeTemplate } from '@nestledjs/forms'

const template = generateThemeTemplate()
// Returns an object with all theme properties set to empty strings
// Fill in with your custom classes

Dynamic themes

Use createFinalTheme for runtime theme resolution:

import { createFinalTheme, tailwindTheme } from '@nestledjs/forms'

function MyForm({ isDarkMode }) {
  const theme = createFinalTheme(
    tailwindTheme,
    isDarkMode ? darkOverrides : lightOverrides,
  )

  return (
    <Form id="form" fields={fields} submit={save} theme={theme}>
      <button type="submit">Submit</button>
    </Form>
  )
}

Per-field styling

In addition to themes, individual fields can be styled with wrapperClassName and customWrapper:

wrapperClassName

FormFieldClass.text('name', {
  label: 'Name',
  wrapperClassName: 'col-span-2 bg-gray-50 p-4 rounded-lg',
})

customWrapper

FormFieldClass.text('highlighted', {
  label: 'Important Field',
  customWrapper: (children) => (
    <div className="rounded-lg border-2 border-yellow-400 bg-yellow-50 p-4">
      <span className="text-xs font-bold text-yellow-800">Priority</span>
      {children}
    </div>
  ),
})

Accessing the theme

Inside custom components, use the useFormTheme hook:

import { useFormTheme } from '@nestledjs/forms'

function CustomField({ value, onChange }) {
  const theme = useFormTheme()

  return (
    <div className={theme.fieldWrapper}>
      <label className={theme.label}>Custom Field</label>
      <input
        className={theme.input}
        value={value}
        onChange={(e) => onChange(e.target.value)}
      />
    </div>
  )
}

Native theming

For React Native, themes use StyleSheet objects instead of class strings. See Field differences for details on native theme format.

Previous
Conditional logic