Comment on page
Edit widgets
This page walks you through all available edit widgets settings.
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
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.
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.
This widget is what you need when handling formatted text. You will be able to decorate your text in bold, italic and much more.

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

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

The number formatting is based on your browser's locale, unless you have a specific locale set in your Project settings.
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:
Use Static content type if you want to manually enter your content.

Your values should be added manually - as a comma-separated list -, unless you enabled the Alter values option (available in 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)

If "Alter values" enabled or field is an enum
Use this option if you want your content to depend dynamically on your data:
Simple mode

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:
SQL
Mongodb

app.js
'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;
decorators/routes/orders.js
// 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;

The five status are displayed in the drop-down menu.
You can add more logic by retrieving the record id or the record type using
request.context.record.id, request.context.record.type
In the example below, the dropdown will only suggest status according to the current status of the order.
decorators/routes/orders.js
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;

Only specific status are displayed based on the previous status of the record.

app.js
'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;
decorators/routes/orders.js
// 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;

The five status are displayed in the drop-down menu.
You can add more logic by retrieving the record id or the record type using
request.context.record.id, request.context.record.type
In the example below, the dropdown will only suggest status according to the current status of the order.
decorators/routes/orders.js
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;

Only specific status are displayed based on the previous status of the record.
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:
While creating a new order, all products are available in the dropdown:

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

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

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.

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

The radio button widget works the same way as the dropdown widget: depending on your field type and whether you used the Alter values option (available in display settings), you will have to manually enter your values or simply toggle them.

Manually entering values

"Alter values" option (display settings)
While editing, the widget will look like this:

The checkboxes widget works the same way as the dropdown widget: depending on your field type and whether you used the Alter values option (available in display settings), you will have to manually enter your values or simply toggle them.

Manually entering values

"Alter values" option (display settings)
While editing, your widget will look like this:

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.

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

- Specific file extensions: restrict which file types your users may upload
- Maximum file size: set a maximum weight for your files
The File picker widget looks like this:

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)
For fields accepting multiple files, a new setting is available: setting a maximum number of files.

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.

In the above picture, the Use these files button will become available after removing the first file by clicking the red cross icon.
If you need to upload large files, you may need to add some code to allow it. Check out this paragraph.
Use this widget if your content is a date.

To validate these date and time, click outside of the widget
Depending on your field type, this might be a Dateonly picker widget.
Use this widget if your content is a color.

Use this widget to handle JSON content.


The full address will be put in a single field (in our above example: description)
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.
The user can then be efficiently displayed using the User display widget.
Both widgets work together to make record assignment easily achievable.
Last modified 3mo ago