# Edit widgets

This page walks you through all available *edit* widgets settings.

{% hint style="info" %}
For an introduction on what widgets are and a comprehensive list of what widgets you'll be able to choose from, check out the previous page: [Customize your fields](/user-guide/collections/customize-your-fields.md)
{% endhint %}

## Text input

Content inputting in its most basic form, the *Text input* is quite what you will find in most online forms.\
For more advanced or specialized content types, see the other widgets.

## Textarea

Much like the *Text input*, the *Textarea* widget is more appropriate when inputting longer portions of text.\
To input formatted content, check out the *Rich text editor* below.

## Rich text editor

This widget is what you need when handling formatted text. You will be able to decorate your text in **bold**, *italic* and much more.

![](/files/-L_rtcHN1dkk4gmA1N2j)

## Price editor

This widget is perfect for editing prices, thanks to a real-time preview of what the formatted number will look like:

![](/files/-MWUiPXP0U6XClgc8exZ)

To set up your widget:

* Choose a currency symbol between **euros** (EUR), **dollars** (USD) and **pounds** (GBP)
* Choose a base: **Cents** if your values are stored in cents, **Unit** otherwise

![](/files/-MWUjMbcoSWHueo-l2Cw)

{% hint style="info" %}
The **number formatting** is based on your browser's locale, unless you have a specific [locale](/user-guide/project-settings/general-tab.md#locale) set in your Project settings.
{% endhint %}

## Dropdown

The dropdown is a very powerful and customizable widget. As you would expect, the result will be a dropdown which allows you to choose between several values.

However, you can customize it in the following ways:

### Static

Use *Static* content type if you want to manually enter your content.

![](/files/-MNTa7Ri7DWcZS7I45nM)

Your values should be added **manually** - as a comma-separated list -, **unless** you enabled the *Alter values* option (available in [display settings](/user-guide/collections/customize-your-fields.md#display-settings)) or if your field is an enum, in which cases you will be able to simply enable/disable values to add them:

!["Alter values" option (display settings)](/files/-MNT_A03DBkWWdTw8RGp)

![If "Alter values" enabled or field is an enum](/files/-MNTZuTtUxJJiUAmgSd2)

### Dynamic

Use this option if you want your content to depend dynamically on your data:

*Simple mode*

![](/files/-MNTc_Jsl-PaOdzC-MvL)

In *Simple mode*, just select which collection you wish to select values from for your dropdown. You can optionally add a filter.

*Dynamic mode*

In Dynamic mode, values will be fetched from your own API endpoint. Here's an example:

{% tabs %}
{% tab title="SQL" %}
![](/files/-Lc0Xo8R6S3ky5JP0WEj)

{% code title="app.js" %}

```javascript
'use strict';
var express = require('express');
var app = express();
var fs = require('fs');

// ...

// You MUST require these files before the default routes.
fs.readdirSync('./decorators/routes').forEach((file) => {
  if (file[0] !== '.') {
    app.use('/forest', require(`./decorators/routes/${file}`));
  }
});

fs.readdirSync('./routes').forEach((file) => {
  if (file[0] !== '.') {
    app.use('/forest', require('./routes/' + file));
  }
});

app.use(require('forest-express-sequelize').init({
  modelsDir: __dirname + '/models',
  envSecret: process.env.FOREST_ENV_SECRET,
  authSecret: process.env.FOREST_AUTH_SECRET,
  sequelize: require('./models').sequelize
}));

module.exports = app;
```

{% endcode %}

{% code title="decorators/routes/orders.js" %}

```javascript
// Configure the dropdown in dynamic mode using this path: /forest/orders/shippingStatusOptions
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-sequelize');

// This is a simple case but you can retrieve your data from an external API or using your own logic
const data = [
  'Being processed',
  'Ready for shipping',
  'In transit',
  'Shipped',
  'Failed',
];

router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, (req, res) => {
  res.send({ data });
});

module.exports = router;
```

{% endcode %}

![The five status are displayed in the drop-down menu.](/files/-Lc0gKQXSWuS7EJwmccg)

{% hint style="info" %}
You can add more logic by retrieving the record id or the record type using `request.context.record.id, request.context.record.type`
{% endhint %}

In the example below, the dropdown will only suggest status according to the current status of the order.

{% code title="decorators/routes/orders.js" %}

```javascript
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-sequelize');
const models = require('../../models');

const STATUS_OPTION_DEFAULT = 'Being processed';
const STATUS_TRANSITIONS = {
  'Being processed': ['Ready for shipping'],
  'Ready for shipping': ['In transit'],
  'In transit': ['Shipped', 'Failed'],
};

router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, async (req, res) => {
  const { context } = req.query;
  const recordId = context && context.record && context.record.id;
  let data = [STATUS_OPTION_DEFAULT];

  if (recordId) {
    const order = await models.orders.findById(recordId);
    const currentShippingStatus = order.shippingStatus;
    if (STATUS_TRANSITIONS[currentShippingStatus]) {
      data = STATUS_TRANSITIONS[currentShippingStatus];
    }
  }
  res.send({ data });
});

module.exports = router;
```

{% endcode %}

![Only specific status are displayed based on the previous status of the record.](/files/-Lc0ghKZZOAd0ZT8iHQe)
{% endtab %}

{% tab title="Mongodb" %}
![](/files/-Lc0Xo8R6S3ky5JP0WEj)

{% code title="app.js" %}

```javascript
'use strict';
var express = require('express');
var app = express();
var fs = require('fs');

// ...

// You MUST require these files before the default routes.
fs.readdirSync('./decorators/routes').forEach((file) => {
  if (file[0] !== '.') {
    app.use('/forest', require(`./decorators/routes/${file}`));
  }
});

fs.readdirSync('./routes').forEach((file) => {
  if (file[0] !== '.') {
    app.use('/forest', require('./routes/' + file));
  }
});

app.use(require('forest-express-mongoose').init({
  modelsDir: __dirname + '/models',
  envSecret: process.env.FOREST_ENV_SECRET,
  authSecret: process.env.FOREST_AUTH_SECRET,
  mongoose: require('mongoose')
}));

module.exports = app;
```

{% endcode %}

{% code title="decorators/routes/orders.js" %}

```javascript
// Configure the dropdown in dynamic mode using this path: /forest/orders/shippingStatusOptions

const express = require('express');
const router = express.Router();
const Liana = require('forest-express-mongoose');

// This is a simple case but you can retrieve your data from an external API or using your own logic
const data = [
  'Being processed',
  'Ready for shipping',
  'In transit',
  'Shipped',
  'Failed',
];

router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, (req, res) => {
  res.send({ data });
});

module.exports = router;
```

{% endcode %}

![The five status are displayed in the drop-down menu.](/files/-Lc0gKQXSWuS7EJwmccg)

{% hint style="info" %}
You can add more logic by retrieving the record id or the record type using `request.context.record.id, request.context.record.type`
{% endhint %}

In the example below, the dropdown will only suggest status according to the current status of the order.

{% code title="decorators/routes/orders.js" %}

```javascript
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-mongoose');
const Order = require('../../models/orders');

const STATUS_OPTION_DEFAULT = 'Being processed';
const STATUS_TRANSITIONS = {
  'Being processed': ['Ready for shipping'],
  'Ready for shipping': ['In transit'],
  'In transit': ['Shipped', 'Failed'],
};

router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, async (req, res) => {
  const { context } = req.query;
  const recordId = context && context.record && context.record.id;
  let data = [STATUS_OPTION_DEFAULT];

  if (recordId) {
    const order = await Order.findById(recordId);
    const currentShippingStatus = order.shippingStatus;
    if (STATUS_TRANSITIONS[currentShippingStatus]) {
      data = STATUS_TRANSITIONS[currentShippingStatus];
    }
  }
  res.send({ data });
});

module.exports = router;
```

{% endcode %}

![Only specific status are displayed based on the previous status of the record.](/files/-Lc0ghKZZOAd0ZT8iHQe)
{% endtab %}
{% endtabs %}

### Relationship

If your field refers to another collection, the dropdown option will automatically populate the data of that collection.\
\
In this example, an **order** `belongs to` a **product**. In **order**'s field settings, you'll find:

![](/files/-Lm5hlsNytwwAEWzESHv)

While creating a new order, all products are available in the dropdown:

![](/files/-Lm9Kd-A7Cs6Ei7Kl8vZ)

You can also **add one or more filters** to display only a dataset of the associated collection.

![](/files/-Lm5irIdZAYKKxqYvQL6)

In this case, only Star Wars products will be available in the dropdown:

![](/files/-Lm9LRVTqy4ubvbTFVb0)

### Enable search

Say you have a *long list* of options to choose from. A dropdown becomes a bit *cumbersome*: this is why we've added this option.

![](/files/-LaVEOOID5fP47dP4DVa)

When enabled, the widget becomes an auto-complete input dropdown.

![](/files/-LaVEDiA4kk4M-dymzzS)

## Radio button

The radio button widget works the same way as the [dropdown](#dropdown) widget: depending on your field type and whether you used the Alter values option (available in [display settings)](/user-guide/collections/customize-your-fields.md#display-settings), you will have to manually enter your values or simply toggle them.

![Manually entering values](/files/-MNTf2YrWTsW5LDsU45r)

!["Alter values" option (display settings)](/files/-MNTeHlXNHovLptrvVax)

While editing, the widget will look like this:

![](/files/-La-kFGQ_O_EVOvt2cRf)

## Checkboxes

The checkboxes widget works the same way as the [dropdown](#dropdown) widget: depending on your field type and whether you used the Alter values option (available in [display settings)](/user-guide/collections/customize-your-fields.md#display-settings), you will have to manually enter your values or simply toggle them.

![Manually entering values](/files/-MNTfZXwxFVLvGfRhE7o)

!["Alter values" option (display settings)](/files/-MNTek1hMRQ0JZJCBFa6)

While editing, your widget will look like this:

![](/files/-La01wWzJMJ6vXewc8PD)

## File picker

Use this widget to upload files (images, pdf,..). This can be done by clicking on the grey rectangle or drag & drop'ing your file in the grey rectangle.

![](/files/-LfUqppUDiMT6IhsdX-M)

### Settings

In your field's settings, you may set the following:

![](/files/-LfUrVwyMwRliKqWDPuB)

* *Specific file extensions:* restrict which file types your users may upload
* *Maximum file size*: set a maximum weight for your files
* *Prefix*: indicate a path to preview your saved files when editing. More on this option [here](/user-guide/collections/customize-your-fields/display-widgets.md#prefix).

### Edit tools

The File picker widget looks like this:

![](/files/-LfUy5mUJ7I_mLEuv2RU)

When uploading a single image, it allows you to perform 2 basic operations before *using this file*:

* Rotate
* Crop (adjust your image's borders until it fit a desired area)

### Upload multiple files at once

For fields accepting multiple files, a new setting is available: setting a maximum number of files.

![](/files/-LfV1qNVdIDszHokucSL)

When uploading multiple files at once, your widget will look like this. Note that uploading multiple files at once will prevent you from using the *rotate* and *crop* features.

![](/files/-LfV5YZRU6mqN52bwezU)

In the above picture, the *Use these files* button will become available after removing the first file by clicking the red cross icon.

### Large files upload

If you need to upload large files, you may need to add some code to allow it. Check out [this paragraph](https://docs.forestadmin.com/woodshop/how-tos/import-data-from-a-csv-file#uploading-large-files).

### Date picker

Use this widget if your content is a date.

![To validate these date and time, click outside of the widget](/files/-L_ru4MrlYV7sTlfVd-r)

{% hint style="info" %}
Depending on your field type, this might be a *Dateonly picker* widget.
{% endhint %}

### Color picker

Use this widget if your content is a color.

![](/files/-L_ru6_WWYQOEjYzMswz)

### JSON editor

Use this widget to handle JSON content.

![](/files/-L_ru8sGUMlmJN6MQG0W)

## Address

This widget allows you to benefit from [Google Places](https://developers.google.com/maps/documentation/places/web-service)'s address autocompletion.

<figure><img src="/files/arMWG4VABEK4qVItArgt" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
The full address will be put in a single field (in our above example: *description*)
{% endhint %}

## User dropdown

This widget allows you to input the email address of a user of the current project.\
You may search for a user using their firstname, lastname or email address.

{% hint style="info" %}
The user can then be efficiently displayed using the [User](https://docs.forestadmin.com/user-guide/collections/customize-your-fields/display-widgets#user) *display* widget.\
\
Both widgets work together to make **record assignment** easily achievable.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/user-guide/collections/customize-your-fields/edit-widgets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
