> ## Documentation Index
> Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin Form Builder API

Spree provides a custom `Spree::Admin::FormBuilder` that extends Rails' standard FormBuilder with additional helper methods designed specifically for the admin interface. This form builder ensures consistent styling, error handling, and behavior across all admin forms.

## Using the FormBuilder

The FormBuilder is automatically available in admin forms when using `form_with`:

```erb theme={"theme":"night-owl"}
<%= form_with model: [:admin, @product] do |f| %>
  <%= f.spree_text_field :name %>
  <%= f.spree_text_area :description %>
<% end %>
```

## Common Options

All FormBuilder methods support these common options:

| Option         | Type              | Description                                                    |
| -------------- | ----------------- | -------------------------------------------------------------- |
| `:label`       | String or `false` | Custom label text, or `false` to hide the label entirely       |
| `:required`    | Boolean           | Adds a red asterisk (\*) indicator next to the label           |
| `:help`        | String            | Help text displayed below the field                            |
| `:help_bubble` | String            | Tooltip text displayed in a help bubble icon next to the label |
| `:class`       | String            | Additional CSS classes for the input element                   |

## Text Input Methods

### spree\_text\_field

Creates a text input field with Spree styling.

```erb theme={"theme":"night-owl"}
<%= f.spree_text_field :name %>
<%= f.spree_text_field :sku, required: true %>
<%= f.spree_text_field :code, help: "Leave blank to auto-generate" %>
<%= f.spree_text_field :slug, help_bubble: "URL-friendly identifier" %>
```

**Options:**

* All standard Rails `text_field` options
* All common FormBuilder options

### spree\_number\_field

Creates a number input field with Spree styling.

```erb theme={"theme":"night-owl"}
<%= f.spree_number_field :price, required: true, step: 0.01 %>
<%= f.spree_number_field :quantity, min: 0 %>
```

**Options:**

* All standard Rails `number_field` options (`:min`, `:max`, `:step`)
* All common FormBuilder options

### spree\_money\_field

Creates a locale-aware money/currency input field with automatic formatting. This field displays amounts in the currency's locale format (e.g., `1.234,56` for EUR, `1,234.56` for USD) and normalizes values to standard decimal format before form submission.

```erb theme={"theme":"night-owl"}
<%= f.spree_money_field :amount, currency: 'USD' %>
<%= f.spree_money_field :price, currency: 'EUR', required: true %>
<%= f.spree_money_field :compare_at_amount, currency: @product.currency, label: false %>
```

**Options:**

| Option      | Type                      | Description                                                                                                                     |
| ----------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `:currency` | String                    | Currency code (e.g., `'USD'`, `'EUR'`, `'PLN'`). Used to determine decimal/thousands separators and display the currency symbol |
| `:value`    | BigDecimal, Float, String | Override the displayed value (will be formatted for the currency's locale)                                                      |
| `:prepend`  | String                    | Text to prepend before the input field                                                                                          |
| `:append`   | String                    | Text to append after the input field (defaults to currency symbol when `:currency` is provided)                                 |
| `:disabled` | Boolean                   | Disable the input field                                                                                                         |

All common FormBuilder options (`:label`, `:required`, `:help`, `:help_bubble`) are also supported.

**Features:**

* **Locale-aware display:** Values are displayed using the currency's decimal mark (e.g., comma for EUR/PLN, dot for USD)
* **Automatic normalization:** Values are converted to standard decimal format (with `.` as decimal separator) before form submission
* **Currency symbol:** Automatically appends the currency symbol when `:currency` option is provided
* **Mobile-friendly:** Uses `inputmode="decimal"` for appropriate mobile keyboard
* **Auto-formatting:** Values are reformatted on blur to ensure consistent display

**Example with nested form:**

```erb theme={"theme":"night-owl"}
<%= f.fields_for :prices do |price_form| %>
  <%= price_form.spree_money_field :amount,
                                   currency: price_form.object.currency,
                                   disabled: !can?(:manage, price_form.object),
                                   label: false %>
<% end %>
```

<Note>
  The money field uses a Stimulus controller (`money-field`) that handles formatting and normalization automatically. The decimal and thousands separators are determined by the currency's ISO standard configuration.
</Note>

### spree\_email\_field

Creates an email input field with Spree styling and HTML5 validation.

```erb theme={"theme":"night-owl"}
<%= f.spree_email_field :email, required: true %>
<%= f.spree_email_field :contact_email,
    help: "For customer support inquiries" %>
```

**Options:**

* All standard Rails `email_field` options
* All common FormBuilder options

## Date and Time Methods

### spree\_date\_field

Creates a date picker input field.

```erb theme={"theme":"night-owl"}
<%= f.spree_date_field :available_on %>
<%= f.spree_date_field :discontinue_on,
    help: "Date when product will be discontinued" %>
```

**Options:**

* All standard Rails `date_field` options (`:min`, `:max`)
* All common FormBuilder options

### spree\_datetime\_field

Creates a datetime picker input field.

```erb theme={"theme":"night-owl"}
<%= f.spree_datetime_field :published_at %>
<%= f.spree_datetime_field :sale_starts_at, required: true %>
```

**Options:**

* All standard Rails `datetime_field` options
* All common FormBuilder options

## Text Area Methods

### spree\_text\_area

Creates a textarea with auto-grow functionality (expands as you type).

```erb theme={"theme":"night-owl"}
<%= f.spree_text_area :description %>
<%= f.spree_text_area :notes, rows: 10 %>
<%= f.spree_text_area :meta_description,
    help: "Used for SEO, maximum 160 characters" %>
```

**Options:**

* `:rows` - Number of visible rows (default: 5)
* `:data` - Data attributes (default includes auto-grow Stimulus controller)
* All standard Rails `text_area` options
* All common FormBuilder options

**Auto-grow behavior:**
By default, the textarea automatically grows as the user types. This uses the `textarea-autogrow` Stimulus controller.

### spree\_rich\_text\_area

Creates a rich text editor using Trix.

```erb theme={"theme":"night-owl"}
<%= f.spree_rich_text_area :description %>
<%= f.spree_rich_text_area :content, label: "Page Content" %>
```

**Features:**

* WYSIWYG editing
* Basic formatting (bold, italic, lists, links)
* File attachments via Active Storage
* All common FormBuilder options

## Select Methods

### spree\_select

Creates a select dropdown field.

```erb theme={"theme":"night-owl"}
<%= f.spree_select :status,
    ['draft', 'active', 'archived'],
    {},
    {} %>

<%= f.spree_select :tax_category_id,
    Spree::Category.pluck(:name, :id),
    { include_blank: 'Select Tax Category' } %>
```

**With autocomplete:**

```erb theme={"theme":"night-owl"}
<%= f.spree_select :country_id,
    Spree::Country.pluck(:name, :id),
    { autocomplete: true } %>
```

**Parameters:**

1. `method` - The attribute name
2. `choices` - Array of options
3. `options` - Select options (`:include_blank`, `:prompt`, `:autocomplete`)
4. `html_options` - HTML attributes (`:class`, `:data`, `:disabled`)

**Options:**

* `:autocomplete` - Enables searchable dropdown with autocomplete functionality
* All standard Rails `select` options
* All common FormBuilder options

### spree\_collection\_select

Creates a select dropdown from a collection of objects.

```erb theme={"theme":"night-owl"}
<%= f.spree_collection_select :shipping_category_id,
    ShippingCategory.all,
    :id,
    :name,
    { include_blank: true },
    {} %>

<%= f.spree_collection_select :tax_category_id,
    TaxCategory.all,
    :id,
    :name,
    { autocomplete: true, required: true },
    {} %>
```

**Parameters:**

1. `method` - The attribute name
2. `collection` - ActiveRecord collection or array of objects
3. `value_method` - Method to call for option value (e.g., `:id`)
4. `text_method` - Method to call for option text (e.g., `:name`)
5. `options` - Select options (`:include_blank`, `:autocomplete`)
6. `html_options` - HTML attributes

**Options:**

* `:autocomplete` - Enables searchable dropdown
* All standard Rails `collection_select` options
* All common FormBuilder options

## Checkbox and Radio Methods

### spree\_check\_box

Creates a styled checkbox with custom controls.

```erb theme={"theme":"night-owl"}
<%= f.spree_check_box :active %>
<%= f.spree_check_box :featured, label: "Feature on homepage" %>
<%= f.spree_check_box :accept_terms, required: true %>
```

**Options:**

* All standard Rails `check_box` options
* All common FormBuilder options

**Styling:**
Uses custom control classes for consistent appearance across the admin interface.

### spree\_radio\_button

Creates a styled radio button with custom controls.

```erb theme={"theme":"night-owl"}
<%= f.spree_radio_button :status, 'draft', id: 'status_draft' %>
<%= f.spree_radio_button :status, 'published', id: 'status_published' %>
```

**Parameters:**

1. `method` - The attribute name
2. `tag_value` - The value for this radio option
3. `options` - Options hash (must include `:id`)

**Options:**

* `:id` - Required HTML ID for the radio button
* All standard Rails `radio_button` options
* All common FormBuilder options

<Warning>
  Radio buttons require unique IDs. Always specify the `:id` option.
</Warning>

## File Upload Methods

### spree\_file\_field

Creates a file upload field with image preview, drag-and-drop support, and optional cropping functionality.

```erb theme={"theme":"night-owl"}
<%= f.spree_file_field :image %>
<%= f.spree_file_field :logo, width: 240, height: 240 %>
<%= f.spree_file_field :avatar, crop: true %>
<%= f.spree_file_field :featured_image, width: 1200, height: 600, crop: true %>
```

**Options:**

| Option                | Type    | Default     | Description                                            |
| --------------------- | ------- | ----------- | ------------------------------------------------------ |
| `:width`              | Integer | 300         | Width of the image preview in pixels                   |
| `:height`             | Integer | 300         | Height of the image preview in pixels                  |
| `:crop`               | Boolean | `false`     | Enable image cropping with recommended size indicator  |
| `:auto_submit`        | Boolean | `false`     | Automatically submit form when file is selected        |
| `:can_delete`         | Boolean | `true`      | Show delete button for removing uploaded image         |
| `:css`                | String  | `''`        | Additional CSS classes for the upload placeholder area |
| `:allowed_file_types` | Array   | Image types | Specify the allowed file types                         |

All common FormBuilder options (`:label`, `:required`, `:help`, `:help_bubble`) are also supported.

**Features:**

* Drag-and-drop file upload
* Image preview after upload
* Optional image cropping with size recommendations
* Delete button to remove uploaded files
* Uses Active Storage direct upload

**Example with all options:**

```erb theme={"theme":"night-owl"}
<%= f.spree_file_field :hero_video_background,
    width: 1200,
    height: 630,
    crop: false,
    auto_submit: false,
    can_delete: true,
    help_bubble: "This video will loop in the background",
    label: 'Hero video background',
    allowed_file_types: %w[video/mp4 video/webm video/ogg] %>
```

## Complete Form Example

Here's a complete example showing various FormBuilder methods:

```erb theme={"theme":"night-owl"}
<div class="card mb-6">
  <div class="card-header">
    <h5 class="card-title">
      <%= Spree.t(:general_settings) %>
    </h5>
  </div>

  <div class="card-body">
    <%= f.spree_text_field :name,
        required: true,
        help: "Product name as displayed to customers" %>

    <%= f.spree_text_field :sku,
        label: "SKU",
        help_bubble: "Stock Keeping Unit - unique product identifier" %>

    <%= f.spree_number_field :price,
        required: true,
        step: 0.01,
        min: 0 %>

    <%= f.spree_rich_text_area :description,
        help: "Detailed product description with rich formatting" %>

    <%= f.spree_collection_select :tax_category_id,
        Spree::TaxCategory.all,
        :id,
        :name,
        { include_blank: 'None', required: true },
        {} %>

    <%= f.spree_date_field :available_on,
        label: "Available Date",
        help: "Date when product becomes available for purchase" %>

    <%= f.spree_check_box :active,
        label: "Active" %>
  </div>
</div>
```

## Error Handling

All FormBuilder methods automatically display validation errors below the field when present:

```erb theme={"theme":"night-owl"}
<%= f.spree_text_field :name %>
```

If `@product.errors[:name]` contains errors, they will be displayed automatically in red text below the input field.

## Internationalization

Labels are automatically translated using Rails I18n. The FormBuilder looks for translations in this order:

1. Custom label passed via `:label` option
2. `spree.{attribute_name}` key
3. `activerecord.attributes.spree/{model_name}.{attribute_name}` key

Example translations:

```yaml theme={"theme":"night-owl"}
# config/locales/en.yml
en:
  spree:
    name: "Product Name"
    sku: "SKU Code"
  activerecord:
    attributes:
      spree/product:
        available_on: "Available On Date"
        discontinue_on: "Discontinuation Date"
```

## Styling and CSS Classes

All FormBuilder methods use consistent styling:

* **Form groups:** Each field is wrapped in a `.form-group` div
* **Input classes:** Text inputs use `.form-control` class
* **Select classes:** Dropdowns use `.custom-select` class
* **Checkboxes/Radios:** Use `.custom-control`, `.custom-checkbox`, `.custom-radio` classes

You can add additional classes via the `:class` option:

```erb theme={"theme":"night-owl"}
<%= f.spree_text_field :name, class: 'form-control-lg' %>
```

## Best Practices

<Check>
  **Use the Spree FormBuilder methods** instead of standard Rails helpers for consistent styling
</Check>

<Check>
  **Add `:required` option** to required fields for visual indication
</Check>

<Check>
  **Use `:help` text** to provide guidance for complex fields
</Check>

<Check>
  **Use `:help_bubble`** for additional context without cluttering the form
</Check>

<Check>
  **Enable autocomplete** on selects with many options (> 20 items)
</Check>
