# Help.Form.io

<h2 align="center">Guides and Documentation</h2>

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><h4><i class="fa-sparkles">:sparkles:</i> <strong>Getting Started</strong></h4></td><td>New to Form.io?<br>Check out the Getting Started Guide.</td><td><a href="/spaces/lzf1MQtQ7rA4uagbyWwi">/spaces/lzf1MQtQ7rA4uagbyWwi</a></td><td></td></tr><tr><td><h4><i class="fa-pen-ruler">:pen-ruler:</i> <strong>Form Building</strong></h4></td><td>A complete guide to building and configuring forms.</td><td><a href="/spaces/6LdEf8SjBIeQDsRL3BdV">/spaces/6LdEf8SjBIeQDsRL3BdV</a></td><td></td></tr><tr><td><h4><i class="fa-gear-code">:gear-code:</i> <strong>Developer Guide</strong></h4></td><td>Render forms, customize the platform, and configure integrations.</td><td><a href="/spaces/DuAwTOTr6NFMpkfgwq9x">/spaces/DuAwTOTr6NFMpkfgwq9x</a></td><td></td></tr><tr><td><h4><i class="fa-badge-check">:badge-check:</i> <strong>Administration &#x26; Portal</strong></h4></td><td>Manage access, configure project settings, and administer teams.</td><td><a href="/spaces/UjxAY3UFi7owqz5ZkVsD">/spaces/UjxAY3UFi7owqz5ZkVsD</a></td><td></td></tr><tr><td><h4><i class="fa-server">:server:</i> <strong>Deployment &#x26; Infrastructure</strong></h4></td><td>Deploy the platform, configure containers, maintain and update the software.</td><td><a href="/spaces/KgNM52jrdfkHgHDfKCH9">/spaces/KgNM52jrdfkHgHDfKCH9</a></td><td></td></tr><tr><td><h4><i class="fa-person-chalkboard">:person-chalkboard:</i> <strong>Tutorials &#x26; Examples</strong></h4></td><td>How-To, samples, and demonstrations of Form.io features.</td><td><a href="/spaces/dE1To8ypyE1yhXEJ7QlD">/spaces/dE1To8ypyE1yhXEJ7QlD</a></td><td></td></tr><tr><td><h4><i class="fa-book-open-lines">:book-open-lines:</i> <strong>Reference Docs</strong></h4></td><td>API docs, error codes, version information</td><td><a href="/spaces/btmdhlZBw7MvpqNP0ZTR">/spaces/btmdhlZBw7MvpqNP0ZTR</a></td><td></td></tr></tbody></table>

<h2 align="center">Other Form.io Resources</h2>

<p align="center">Find Form.io resources around.</p>

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-github">:github:</i></h4></td><td><strong>GitHub</strong></td><td>Explore Form.io Open Source, and other repos</td><td></td><td><a href="https://github.com/formio">https://github.com/formio</a></td></tr><tr><td><h4><i class="fa-youtube">:youtube:</i></h4></td><td><strong>YouTube</strong></td><td>See walkthroughs, demos, and more.</td><td></td><td><a href="https://www.youtube.com/@Form_io">https://www.youtube.com/@Form_io</a></td></tr><tr><td><h4><i class="fa-message-question">:message-question:</i></h4></td><td><strong>Support</strong></td><td>Contact support for further assisstance.</td><td></td><td><a href="https://form.io/enterprise-support/">https://form.io/enterprise-support/</a></td></tr></tbody></table>

{% columns %}
{% column %}
Form.io offers a variety of resources to help users succeed.

Refer to the following guides to learn about the platform, discover new features, and resolve issues.
{% endcolumn %}

{% column %}
{% embed url="<https://www.youtube.com/watch?v=zyP0cTkppY8>" %}
{% endcolumn %}
{% endcolumns %}


# What is Form.io?

The first stop for users who are new to Form.io or exploring the platform.

Welcome to **Form.io!**

**Form.io** is a combined form and data management platform that creates sophisticated forms, exposes them through automatically generated APIs, and routes submission data to the systems that need it. It allows application developers to rapidly create forms using a flexible palette of drag-and-drop components. Alongside this form, Form.io generates the API necessary to collect and handle the data collected by the form.

### Popular topics

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-video">:video:</i> Platform Adoption</h4></td><td>A video series covering the major milestones on the road to using Form.io</td><td></td><td></td><td><a href="/pages/Sg8QgWTd8HBBcIeG0F1e">/pages/Sg8QgWTd8HBBcIeG0F1e</a></td></tr><tr><td><h4><i class="fa-user-question">:user-question:</i> Concepts</h4></td><td>Learn about Form.io fundamentals</td><td></td><td></td><td><a href="/pages/VJdbrPy2x4RYKWk2hQdg">/pages/VJdbrPy2x4RYKWk2hQdg</a></td></tr><tr><td><h4><i class="fa-chart-diagram">:chart-diagram:</i> Platform Architecture</h4></td><td>Learn about the structure of Form.io</td><td></td><td></td><td><a href="/pages/kdIha9GueSQ0hSXC3kDO">/pages/kdIha9GueSQ0hSXC3kDO</a></td></tr></tbody></table>


# Platform Adoption Overview

The four key milestones on the road to adopting Form.io

With a license key in hand, there are four major milestones on the path to adopting the Form.io Platform. The following video provides a high-level overview of each of these steps:

{% embed url="<https://www.youtube.com/watch?v=jFY-B6yY3ys>" %}

For more detailed information and additional resources describing each of these milestones, refer to the following sections:

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center">Milestone 1:<br>Getting the platform running</td><td><a href="/files/Fw39q3NQlrW3ZNqbHViJ">/files/Fw39q3NQlrW3ZNqbHViJ</a></td><td><a href="#milestone1">#milestone1</a></td></tr><tr><td align="center">Milestone 2:<br>Authenticating Into the Developer Portal</td><td><a href="/files/bFyIFQFEWle4nbYAw98e">/files/bFyIFQFEWle4nbYAw98e</a></td><td><a href="#milestone-2-log-into-the-developer-portal">#milestone-2-log-into-the-developer-portal</a></td></tr><tr><td align="center">Milestone 3:<br>Create &#x26; Embed a Form</td><td><a href="/files/PuoPsJx0JJMpczbm2F1b">/files/PuoPsJx0JJMpczbm2F1b</a></td><td><a href="#milestone-3-create-and-embed-a-form">#milestone-3-create-and-embed-a-form</a></td></tr><tr><td align="center">Milestone 4:<br>Incorporate Integrations</td><td><a href="/files/CHZV7pJzdWhm4lxwTPU7">/files/CHZV7pJzdWhm4lxwTPU7</a></td><td><a href="#milestone-4-incorporate-essential-integrations">#milestone-4-incorporate-essential-integrations</a></td></tr></tbody></table>

### Milestone 1: Get the Platform Running <a href="#milestone1" id="milestone1"></a>

Deploy the Form.io Docker containers — locally or to the cloud — and begin the journey!

{% embed url="<https://www.youtube.com/watch?v=PF2JTe_xsGY>" %}

**Resources-** Form.io Deployment guides:

* [Local Deployment](/deploy/local-deployment)
* [AWS Deployment](/deploy/cloud-deployment/aws-deployment)
* [Azure Deployment](/deploy/cloud-deployment/azure-deployment)
* [GCP Deployment](/deploy/cloud-deployment/gcp-deployment)

**Objective -** After following the deployment guide, the Form.io Platform should be available in the chosen environment with the Developer Portal accessible.

### Milestone 2: Log into the Developer Portal

With the platform in place, it's time to get in! Log in to the Developer Portal as the admin user and begin configuring additional users.

{% embed url="<https://www.youtube.com/watch?v=PKS74BfO8tg>" %}

**Resources -**

* [Portal Base Project](/deploy/portal-base-project)
* [User Resource](/form-building/resources-readme)
* [Portal SSO](/dev/authentication-and-authorization)
* [Teams](/admin/teams)

**Objective -** Authenticate into the Form.io Developer Portal as the admin user created during deployment. Create or onboard additional users.

### Milestone 3: Create & Embed A Form

Once the team is onboarded, it's time to get hands-on. Start by building a form and see how it embeds right into a custom application.

{% embed url="<https://www.youtube.com/watch?v=SjZ5O8dMe98>" %}

**Resources:**

* [Form Building](https://help.form.io/form-building/)
* [Roles and Permissions](/admin/roles-and-permissions)
* [Embedding a Form](/dev/form-embedding)
* [Authentication and Authorization](/dev/authentication-and-authorization)

**Objective -** Build a form and embed it in a application.

### Milestone 4: Incorporate Essential Integrations

Connect the Form.io Platform to other tools and services to get the most out of it! Integrations can store form-user uploads, email submission data to a recipient, and use webhooks to push data to other parts of the application ecosystem.

{% embed url="<https://www.youtube.com/watch?v=JN9gqSHFu4Y>" %}

**Resources:**

* [File Storage](/dev/integrations/file-storage)
* [Email Integrations](/dev/integrations/email-integrations)
* [Webhook](/form-building/actions/webhook-actions)

**Objective -** Use the Form.io Developer Portal to connect to any additional services or applications that may be necessary.


# Platform Architecture

A simple overview of the Form.io Platform architecture

Form.io is a fully containerized platform. Everything runs as Docker containers that can be deployed on-premise, in the cloud, or even locally to a single machine. At the core, an environment is a handful of services connected over a Docker network, each handling a distinct responsibility.

<figure><img src="/files/fwbINkBiPs7Kx7AmasZj" alt="A diagram of the Form.io Platform Architecture. A load balancer connects to three instances of the Form.io Multi-container Docker Service. Each Multicontainer instance is comprised of an Enterprise container and a PDF container. The collection of Multicontainers feeds the DB cluster."><figcaption><p>An overview of the Form.io Platform</p></figcaption></figure>

## **The Enterprise Container**

**The Enterprise API server** (`formio/formio-enterprise`, port 3000) is the heart of the platform. It serves the REST APIs for creating and managing forms, manages the storage and retrieval of submissions, and handles user authentication.

When enabled, it hosts the **Developer Portal**, a web-based UI where form builders visually design forms, manage projects, configure roles, and promote forms across stages. Whether the portal is enabled or not is controlled by an environment variable configured at deployment. Production instances often run without the portal, keeping it as a pure API endpoint for applications.

## **The PDF Container**

**The PDF server** (`formio/pdf-server`, port 4005) is a separate container dedicated to rendering PDFs. It handles uploading existing PDF documents and overlaying Form.io web forms on top of them, as well as generating PDF exports of form submissions. It uses a headless browser (Puppeteer) internally to render forms into PDF format. Both the API server and the PDF server connect to the same database where data is ultimately stored.

## DB Layer

**MongoDB** is the database layer. All form definitions (stored as JSON), submissions, user accounts, project configurations, and the Portal Base project data live here.

In production deployments, this is typically a managed MongoDB service (MongoDB Atlas, Azure Cosmos DB, AWS DocumentDB), but for local development it can run as a simple Docker container with a mounted volume.

## Additional External Services

### Storage

**S3-compatible file storage** handles binary files, like file uploads from form users, or stored PDF documents. Form.io supports a variety of storage options:

* AWS S3, directly
* Azure Blob Storage
* Self-hosted S3-compatible servers, like SeaweedFS or MinIO.

The PDF server in particular relies on this for storing generated PDF files.

### NGINX

**NGINX** (or another reverse proxy) sits in front of the API and PDF containers, routing all incoming HTTP/HTTPS traffic to the correct service. Requests to the root path go to the API server, requests to `/pdf/` are rewritten and forwarded to the PDF server, and file storage traffic can be routed to the desired storage service or domain. This lets the entire environment sit behind a single URL.

## What lives on the client side

The **Form Renderer** is a JavaScript SDK (available for vanilla JS, Angular, and React) that is embedded directly into an application. It takes the JSON form definition from the API and transforms it into a fully interactive, validated form in the browser.

All rendering, validation logic, and conditional behavior run client-side. The renderer talks back to the API server only to fetch form definitions and submit completed data.

### Multi-environment deployments

A typical enterprise setup uses a **3-environment license**: Development, Test/Authoring, and Production. The Test environment is where the Developer Portal lives, providing a stable place for form builders to work.

Stages within a project let teams promote forms from one environment to the next. Each environment has an independent API server, PDF server, and database, all connected through the portal UI using remote connections secured by a shared portal secret.

This architecture means form builders work in the portal, developers embed the renderer in their apps, and the Enterprise and PDF servers handle everything in between. This effectively separates Form.io platform development, form building, and application development, preventing issues in one from bottlenecking another.


# Form.io Concepts

Defining key concepts and terminology in Form.io

## Forms

A **Form** is the primary way data enters the platform. Forms are built using the drag-and-drop Form Builder to arrange **components**, which can be thought of as the fields that make up a for&#x6D;**.**

Forms may be created in three display modes:

* **Web Form** - a standard single-page form.
* **Wizard** - displays a web form in a multi-step format with navigation between pages.
* **PDF** - a fillable PDF that overlays Form.io components on a document.

As a form is built Form.io simultaneously constructs the JSON schema and defines a REST API endpoint. This allows the form to be fully portable, embeddable, and programmatically accessible.

Forms collect "ad hoc" data, generally through a form user's input.

***

## Resources

A **Resource** is a structured data object within a project. Resources are built using the same drag-and-drop Form Builder to arrange components. Resources are used to define reusable data models that other forms and resources can reference.

Think of a Resource as a database collection with a built-in schema. Common examples include:

* A **User** resource that stores name, email, and a role for application users.
* A **Customer** resource that might be used across multiple forms such as orders, returns, and support.
* A **Product** resource that populates the selections available on an Order form.

Once a Resource is populated with submission data, it functions like a RESTful database. Entities can be created, read, updated, deleted, and queried through the same automatically generated API. Other forms can reference Resource data using components like the **Select Resource** field, enabling complex relational data structures.

Forms vs. Resources — when to use which:

<table><thead><tr><th width="202.62890625"></th><th>Forms</th><th>Resources</th></tr></thead><tbody><tr><td><strong>Function</strong></td><td>Collect unstructured / supplemental data</td><td>Define structured, reusable data objects</td></tr><tr><td><strong>Examples</strong></td><td>Job application, feedback survey</td><td>Employee profile, Cost Center list</td></tr><tr><td><strong>Referenced by others?</strong></td><td>Rarely</td><td>Frequently, resources populate form fields</td></tr><tr><td><strong>Typical use</strong></td><td>One-time or event-driven submissions</td><td>Persistent records queried by the application</td></tr></tbody></table>

***

## Components

**Components** are the building blocks of every form and resource. Components are dragged from the palettes of available components onto the Form Builder canvas. Components capture input through a variety of fields. Each component is stored as a JSON object within the form's schema, and defines how the input is stored in submission data.

Every component can be configured in a variety of ways to customize the appearance and functionality, altering the way the field appears, the way data is validated, and more.

Developers who need functionality beyond the built-in library can create **custom components** by extending an existing component class and registering it with the renderer.

***

## Projects

A **Project** is the top-level organizational unit in Form.io. Typically, a single project corresponds to a single application. All collateral developed in Form.io (forms, resources, roles, submission data) are contained within a project. Projects shares a single domain API endpoint.

Projects serve as a scope boundary for Form.io users. A particular form builder might be granted permission to create forms in one project but not another, while a form user may view submissions in one project but not others. Every element within a project is encapsulated within that project's context; roles, data, and permissions in one project are distinct to that project, and cannot be shared or accessed from a different project.

A project can contain an unlimited number of forms, resources, and developers, and can handle an unlimited number of API submission calls.

***

## Developer Portal

The **Developer Portal** is the web-based UI where platform users manage everything: projects, forms, resources, roles, submissions, stages, teams, and integrations. It is the primary interface for form builders and developers during the build phase.

Form users (the people who fill out forms in production) do **not** interact with the Developer Portal. They access forms through the application that embeds and renders them using the Form.io JavaScript renderer.

***

## Form JSON

Every form and resource in Form.io is represented under the hood as Form JSON. Form JSON is a JSON object that describes the form's title, display type, API path, and the full tree of components with their settings, validation rules, conditional logic, and layout.

A simplified example:

```json
{
  "title": "Person",
  "display": "form",
  "type": "form",
  "name": "person",
  "path": "person",
  "components": [
    {
      "type": "textfield",
      "key": "firstName",
      "label": "First Name",
      "input": true
    },
    {
      "type": "email",
      "key": "email",
      "label": "Email",
      "input": true
    },
    {
      "type": "button",
      "key": "submit",
      "label": "Submit",
      "action": "submit",
      "input": true
    }
  ]
}
```

The JSON schema is the single source of truth for a form. It powers three critical functions:

1. **Rendering -** The JavaScript form renderer reads the JSON and displays the form in the browser. No server-side rendering is needed as the form is fully described by its schema.
2. **API generation -** The server uses the same JSON to generate the REST API endpoints and validate incoming submission data.
3. **Portability -** Because the form is just JSON, it can be versioned, exported, imported, migrated between stages, and stored in source control.

The Form Builder UI updates the JSON schema in real time as components are arranged and configured.

***

## Submissions

A **Submission** is a single data record created when a user fills out and submits a form or resource. The submission payload is a JSON object whose structure mirrors the `key` values defined in the form's components.

In the "Person" form example above, a submission would look like:

```json
{
  "data": {
    "firstName": "Jane",
    "email": "jane@example.com"
  }
}
```

Submissions are the data layer of the platform. Submissions are:

* **API-accessible** - Every submission is reachable via the REST API at a URL of the form `{projectUrl}/{formPath}/submission/{submissionId}`.\
  Submissions can be created, read, updated, deleted, filtered, and paginated through the API.
* **Owned** - Each submission has an owner (the user who created it), which is used by the permissions system to enforce \_own vs. \_all access control.
* **Portable** - In addition to API access, submission data can be viewed in JSON, CSV, or PDF formats directly from the Developer Portal.
* **Revision-tracked** - Submission Revisions (available with the Security & Compliance package) provide an audit log of who changed a submission, when, and what was modified, with the ability to revert to previous versions.
* **Collection-configurable** - Submissions can optionally be directed to separate database collections on a per-form basis for compliance or performance requirements.

***

## Actions

**Actions** are configurable server-side operations that execute when a form is submitted. Every form can have an unlimited number of actions that execute sequentially. Actions can be used as a bridge to other parts of an application or integrated systems.

Actions are where integration and workflow logic lives. The built-in actions include:

* **Save Submission -** Saves the submission data. By default every form has this action, saving data to itself. It can also be configured to route data to a different Resource (e.g., a Registration form that saves to a User resource).
* **Email -** Sends an email using a configured email transport (SMTP, SendGrid, Mailgun, or Mandrill) with customizable templates that can include submission data.
* **Login -** Authenticates a user by generating a JWT token based on the submitted credentials.
* **Webhook -** Sends the submission payload to an external API endpoint in real time, enabling integration with any external system.
* **Integrations -** Sends submission data to third-party providers.

***

## Roles & Permissions

Form.io uses a **role-based access control (RBAC)** system to govern who can do what within a project. The system is built on two concepts: **Roles** (which are assigned to users) and **Permissions** (which are given to roles).

### Roles

Every new project starts with four default roles:

* **Anonymous** - Reserved for unauthenticated users (e.g., someone filling out a public survey or a login form). Cannot be deleted.
* **Everyone** - A role that represents any user assigned to any role, including anonymous ones. When a permission is given to **Everyone**, every role in the project inherits that permission. Cannot be deleted.
* **Authenticated** - A starting role for logged-in users.
* **Administrator** - A starting role for users with elevated privileges.

Additional custom roles can be added. Each role has a unique ID scoped to its project. Roles exist within the Project context and cannot cross project boundaries.

### Permissions

Permissions are organized across three scopes:

<table><thead><tr><th width="282.39453125">Scope</th><th>What it controls</th></tr></thead><tbody><tr><td><strong>Project</strong></td><td>Who can create, read, update, or delete project-level elements (forms, roles, settings).</td></tr><tr><td><strong>Form Definition</strong></td><td>Who can read, update, or delete a specific form's JSON schema.</td></tr><tr><td><strong>Submission Data</strong></td><td>Who can create, read, update, or delete the data submitted through a specific form.</td></tr></tbody></table>

Within each scope, eight permission types are available:

| Own        | All        |
| ---------- | ---------- |
| Create Own | Create All |
| Read Own   | Read All   |
| Update Own | Update All |
| Delete Own | Delete All |

"Own" permissions restrict users to records they own (typically records they created). "All" permissions grant access to all records, regardless of ownership.\
As a general rule, "All" permissions are for administrative roles and "own" permissions are for end users.

{% hint style="info" %}
By default, forms allow all roles to *read* the form definition (so the form can be rendered in the application), but submission access is disabled for every form. You must explicitly grant submission permissions for users to interact with a form's data.
{% endhint %}

***

## Teams

**Teams** enable collaboration by granting groups of developers and form builders access to projects and stages. A team is created at the portal level (outside any individual project). Teams can then be assigned to one or more projects.

Teams can operate at two levels:

* **Project-level** - Grants the team access to the entire project.
* **Stage-level** - Grants the team access to a specific stage of a specific project (e.g., the Development stage) without access to other stages like Live.

Stage-level teams support two permission tiers: **Stage Read** (view forms and data, but cannot modify) and **Stage Write** (view and modify forms and data).

***

## Stages

**Stages** deliver control over a project's development lifecycle, such as authoring, testing, and production. By default, every project has a **Live** stage that represents the production environment.

Additional stages can be created to match a team's SDLC. A typical configuration includes:

| Stage           | Purpose                                                                                           |
| --------------- | ------------------------------------------------------------------------------------------------- |
| **Live**        | The production stage connected to the production environment.                                     |
| **Authoring**   | Where form builders create and modify forms before they are ready for testing.                    |
| **QA / Test**   | Where stage versions are deployed and tested in a live-like environment before promotion to Live. |
| **Development** | A dedicated stage for developers to test new platform releases or application changes.            |

Each stage can be connected to its own **Environment** (a separate backend with its own database and Form.io server containers), or multiple stages can share an environment. **Stage Versions** allow you to snapshot a project's forms, resources, actions, and roles and deploy that version from one stage to another, enabling controlled promotion workflows.

Stages can also be placed in **Protected Mode**, which prevents modifications to forms, resources, roles, and project access, often used for any stage connected to a live application.

***

## The API Layer

One of Form.io's defining characteristics is that every form and resource automatically generates a full REST API. There is no separate step to define or deploy an API. The API is created alongside the form and is functional the moment the form is saved.

### API URL Structure

The API is hierarchical, mirroring the project > form >submission structure:

<table><thead><tr><th width="170.45703125">Scope</th><th>URL Pattern</th><th width="336.41015625">Example</th></tr></thead><tbody><tr><td><strong>Project</strong></td><td><code>{baseUrl}/{projectName}</code></td><td><code>https://myenv.com/hrapp</code></td></tr><tr><td><strong>Form / Resource</strong></td><td><code>{projectUrl}/{formPath}</code></td><td><code>https://myenv.com/hrapp/employee</code></td></tr><tr><td><strong>Submission</strong></td><td><code>{formUrl}/submission/{id}</code></td><td><code>https://myenv.com/hrapp/employee/submission/abc123</code></td></tr><tr><td><strong>Action</strong></td><td><code>{formUrl}/action/{id}</code></td><td><code>https://myenv.com/hrapp/employee/action/def456</code></td></tr><tr><td><strong>Role</strong></td><td><code>{projectUrl}/role/{id}</code></td><td><code>https://myenv.com/hrapp/role/ghi789</code></td></tr></tbody></table>

Standard HTTP methods apply: `GET` to read, `POST` to create, `PUT` to update, `DELETE` to remove. Submissions support filtering, pagination, and sorting through query parameters.

### Authentication

API requests are authenticated using **JSON Web Tokens (JWT)**. When a user logs in through a Form.io Authentication (usingLogin action) or an OAuth/SAML/LDAP flow, the platform issues a JWT that is included in subsequent API requests as an `x-jwt-token` header. The server evaluates the token to determine the user's roles and enforces the permission rules described above.

### JavaScript SDK

The platform provides a JavaScript SDK (`Formio` class) that wraps the API and provides convenient methods for common operations. The SDK mirrors the hierarchical URL structure:

```js
// Project scope
const project = new Formio('https://myenv.com/hrapp');

// Form scope
const form = new Formio('https://myenv.com/hrapp/employee');

// Submission scope
const submission = new Formio('https://myenv.com/hrapp/employee/submission/abc123');
```

The SDK is used internally by the Form.io renderer and is also available for direct use in application code.

### API Explorer

The Developer Portal includes a built-in **API Explorer** (powered by Swagger) that visualizes all the API endpoints generated by the forms and resources in your project. It is a live explorer — requests made through it execute against the real API.

***

## Multi-Tenancy

For SaaS and multi-tenant applications, Form.io supports **Multi-Tenancy.** This offers the ability to create isolated tenant sub-projects within a single parent project. Each tenant functions as a self-contained project with its own API endpoint, forms, resources, data, authentication, file storage, and access permissions, while inheriting CORS settings from the parent project.

This architecture allows a single deployment to serve multiple customers or organizational units, each with full project-level isolation, managed from a unified Developer Portal interface.

***

## Customer Applications

Through most Form.io documentation **Application** refers to the Application that developers are building outside of **Form.io**, and which will embed the Form.io Rendered.

**Form.io** major components are created within the **Form.io** system, but are ultimately used in the customer Application. It is important to distinguish a customer Application from the work being completed within **Form.io**.

***

## How It All Fits Together

The diagram below summarizes the relationships between these concepts:

```
Project
├── Forms ──────────── (built via Form Builder, stored as JSON Schema)
│   ├── Components     (drag-and-drop fields that define data structure)
│   ├── Actions        (server-side operations: save, email, webhook, login…)
│   ├── Submissions    (data records created by form users, accessible via API)
│   └── Access         (per-form permission assignments using Roles)
│
├── Resources ──────── (structured data objects, same builder as Forms)
│   ├── Components
│   ├── Actions
│   ├── Submissions
│   └── Access
│
├── Roles ─────────── (Anonymous, Authenticated, Administrator, custom…)
├── Stages ────────── (Live, Authoring, QA, Development…)
├── Teams ─────────── (groups of users with project/stage access)
└── API ───────────── (auto-generated REST endpoints for every form & resource)
```


# Launch a Form

This section walks you through how to launch a form for the public to submit.

Launching a form allows you to create a form or survey, and quickly launch it so that end users can submit that form. For example, let's say you simply wish to have a number of people fill out an Employment Application form, the Form.io form launching system enables this by providing a public web-based portal for these potential applicants to submit their candidacy for the positions you may have available. You can also configure a number of actions that are triggered once the form is submitted, such as sending an email to both the candidate as well as the HR administrator who will then process the application.

In this tutorial, we will create an Employment Application form, setup a few Email actions, and then launch it so that potential employees can fill out the form to submit their candidacy.

## Step 1: Create a project

To get started, let's create a new **Project** called **Employee Portal.** We can do this by navigating to <https://portal.form.io> and create a new account, or login to an existing account. The first page you see will have a button that says **New Project**

![Create a new project](/files/MchjFZ74BkHNs14gFCX8)

![](/files/Sa4AuNyuB8mWgSxGdVpt)

## Step 2: Create a Form

Once you create a new project, you can now go to the **Forms** section, and create a **New Form**.

![Adding a new form](/files/SLhvgH3VBcV3STiHum8Z)

Next we will select API Web form as the type of form we will be creating.

![](/files/K7ZNc25rxdR6N9jN1ytL)

Next, we will provide a **Title** for our form, **name**, and **path**. These are defined as follows.

* **Title** - This is the human readable title provided for the form to assist in management and end users to know the form they are submitting.
* **Name** - This is the machine name for this form, that is useful when performing API requests to manage the form as well as importing the forms into other projects.
* **API Path** - This is the API path for this form, which is used when embedding the form as well as referencing users to submit the form.

![Adding a new form with title, name, and API path.](/files/7agiWy2iWJSzKavtqhka)

Next, we will add a few fields to this form. Each field type is documented in further detail in the[ **Form Building User Guide**](https://help.form.io/form-building/). For now we will just create a simple form with a few fields as follows.

![](/files/JAZIiMaTcDJk6FTAWTEc)

Next we will click **Create Form** to create our new form.

## Step 3: Create some Actions

Next, we will click on the **Actions** tab, and then select **Email** and click **Add Action**.

![Adding an Email actions](/files/QxQdEAsHo4XJWKw2yZlf)

The first thing we will do is configure the [**Email Transport**](/dev/integrations/email-integrations) that will be used to fire off our emails. Email Transports are 3rd party email servers that will handle the sending of emails from the Email Action and are configured separately from Form.io.

Next, set the "To: Email Address" that will send an email to the person who filled out the application. We can reference fields within the Form by using the following syntax.

```
{{ data.email }}
```

Any field can be referenced this way by referring to the fields "Property Name" which can be found within the API tab when you edit any field within the form.

![](/files/3s8vnrEbFerrJf6XA0Oc)

After we have done this, we will now set the **Subject** of the email to say "Thank you for your registration!".

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

Click on **Save Action** at the bottom of the page. You should now see the following.

![](/files/RqC384eFmF3KHW108gUc)

Next, we will show how you can stack Actions on top of one another by simply just adding another action to the list. A good example of why we may want to do this is if we wish to send an email to the Human Resources department for each application submitted, so we will just simply repeat the steps above (to create a new Email action) but with the following configurations.

* **Title:** Send email to HR
* **To: Email**: <hr@example.com>
* **Subject**: We have a new application!

When we are done, our actions should look like the following.

![](/files/BLyoJLnECGMMiUd8b0oc)

Next, we will need to configure the Access of this form so that anonymous users can submit the form.

## Step 4: Configuring Access

To configure the Access of our form to allow anonymous users to submit it, we must first click on the Access tab, and then add **Anonymous** to the **Create Own Submissions** permission.

![Allowing anonymous users to submit this form.](/files/Ov3yyOws9NGI4imoglNR)

There are many other things we can do with the Access section of a form, so we recommend reading the [**Roles and Permissions**](/admin/roles-and-permissions) Guide at a later time. We are now finally ready to launch our form!

## Step 5: Launch the form

Launching a form enables the form that we just created to be hosted within a special application, called FormView, that provides a way for end users to submit the form. The FormView application is permanently hosted at the <https://pro.formview.io> domain. We can launch our form by clicking on the **Launch** tab.

The form can now be shared with others by copying the URL provided next to the blue button. We can also click on this button, which will navigate our browser to this form so that we can see how end users will experience our form and fill it out.

![Click the blue button to navigate to the form](/files/usJya0XSeGbudGyMjauc)

Congratulations! We have just launched our form and others can now submit it!

![Launching a form within https://pro.formview.io](/files/vK3bunaat8SB7dloZ8dY)

There are many other things we can do with our FormView application, such as White Labeling, changing the logo, navigating to a thank you page, etc. For more information about our FormView application, please check out the [**FormView User Guide**](/form-building/form-view-pro/formview).


# Working with Support

Form.io is committed to user success. To help ensure the best experience with the Form.io Platform, there are a variety of options to resolve any issues that may arise in the course of deployment, development, or production.

## Web Help

Many routine questions can be answered through the content available in the online help at [Help.Form.io](https://github.com/formio/gitbook-docs/blob/main/quick-links.md).

Additionally, many [video walkthroughs and tutorials](https://www.youtube.com/channel/UCA_81zGqS4EdrkK0UvLCubg) are available to offer a visual guide to the essential functions of the Form.io Platform.

## Email Support

Form.io providers customer email support at <support@form.io>.\
Email support is typically available Monday through Friday, 9:00 AM - 5:00 p.m. Central time. Holiday closures may apply.

### Scope of Email Support

Email support can resolve most issues a customer may encounter in their use of the Form.io Platform. Email support can help troubleshoot, diagnose, and resolve issues that arise in during system deployment, form development, and application integration.

Some issues may be related to customer environments, external applications, or customized code or workflows. While Form.io Support will always endeavor to provide customers with meaningful and actionable advice in these instances, Support may be unable to resolve issues outside of the scope of the Form.io Platform.

If the process of resolving a case identifies an additional or unrelated issue, support may require that this be tracked as a separate support case.

### What to include when contacting support

When new or unpredicted issues arise, Support will often try to recreate the behavior on an internal environment. Email support is unable access customer environments. For this reason, it is important to provide as much detail as possible to give the Support team the necessary information so that they can fully understand and attempt to reproduce the issue.

Depending on the issue that is encountered, it may be important to include the following information:

* Form.io product versions
  * Enterprise Server version
  * PDF Server version
  * Form render version
* Environment information
  * Hosting environment
  * Relevant network configurations
  * Framework/library versions
* Browser details
  * Browser name and version
  * Console/dev tool logs
* Specific error messages, if present
* JSON file of Form Definition
  * Try to remove any components unrelated to the issue
* Submission JSON
* Exports of Project JSON

### Using JSFiddle

It is often helpful to demonstrate an issue through [JSFiddle](https://jsfiddle.net/).

JS Fiddle is a third-party application that allows users to demonstrate a live example of JS/CSS/HTML. This is useful for describing issues that arise with the display or behavior of an individual component of a form.

Demonstrating unexpected behavior in a JSFiddle can help ensure the issue is reproducible. Try to only include the minimum components necessary to recreate the issue.

### Using CodeSandbox

[CodeSandbox](https://codesandbox.io/) is a third-party tool that helps create a portable sandboxed environment. This can be useful when describing issues at the application level.

## Support Packages

If Email Support is unable to reproduce an issue outside of the customer form or environment, or when an issue is otherwise determined to be outside of the scope of Email Support, customers may request such support via a customized support packages defined on a case-by-case basis in a separate agreement with Form.io.


# Form Building Guide

The Form Building Guide is a comprehensive resource for building forms and resources in the Form.io Platform. It covers everything from the fundamentals of building a form to conditional logic and validation. [Test link minimal](/admin/licensing/library-licenses) [Test Link empty](/admin/licensing/library-licenses) [Library Licenses](/admin/licensing/library-licenses) [Test Link other text](/admin/licensing/library-licenses)

### Popular Topics

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Form Builder</strong></td><td>Create forms from an array of components</td><td></td><td></td><td><a href="/pages/2Tc1YWBxLMafiiifwrpj">/pages/2Tc1YWBxLMafiiifwrpj</a></td></tr><tr><td><strong>Component Reference</strong></td><td>Learn how to user and configure the elements of a Form</td><td></td><td></td><td><a href="/pages/3QZQFSOCYUdB8xZo2LfA">/pages/3QZQFSOCYUdB8xZo2LfA</a></td></tr><tr><td><strong>Resources</strong></td><td>Learn about Resources, Form.io's structure data object</td><td></td><td></td><td><a href="/pages/7otNn874DMzx7dzogRH5#what-are-resources">/pages/7otNn874DMzx7dzogRH5#what-are-resources</a></td></tr></tbody></table>


# Form JSON

Form JSON defines the structure, appearance, and functionality of a form.

Form JSON is the schema automatically created by the Form Builder.

Every component added through the Form Builder is added to the JSON Schema behind the Form. It records every component, that component's settings and customizations, as well as how that component is organizared or structured within the form.

The JSON Schema is then used in several ways:

* **Rendering** the forms within a website/application .
* **Generating** the **REST** **API** interfaces on the server.
* Hosting the form's JSON schema at the **Embed** **URL.**

An example of a form and the resulting JSON is included below:

#### Form

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

#### Resulting JSON

```json
{
  "title": "Race Registration",
  "name": "raceRegistration",
  "path": "raceregistration",
  "type": "form",
  "display": "form",
  "components": [
    {
      "title": "Entrant Info",
      "collapsible": false,
      "key": "entrantInfo",
      "type": "panel",
      "label": "Panel",
      "input": false,
      "components": [
        {
          "label": "Columns",
          "columns": [
            {
              "components": [
                {
                  "label": "First Name",
                  "applyMaskOn": "change",
                  "validate": {
                    "required": true
                  },
                  "validateWhenHidden": false,
                  "key": "firstName",
                  "type": "textfield",
                  "input": true
                }
              ],
              "width": 6,
              "size": "md",
              "currentWidth": 6
            },
            {
              "components": [
                {
                  "label": "Last Name",
                  "applyMaskOn": "change",
                  "validate": {
                    "required": true
                  },
                  "validateWhenHidden": false,
                  "key": "lastName",
                  "type": "textfield",
                  "input": true
                }
              ],
              "width": 6,
              "offset": 0,
              "size": "md",
              "currentWidth": 6
            }
          ],
          "key": "columns",
          "type": "columns",
          "input": false,
          "tableView": false
        },
        {
          "label": "Age",
          "applyMaskOn": "change",
          "mask": false,
          "tableView": false,
          "delimiter": false,
          "requireDecimal": false,
          "inputFormat": "plain",
          "truncateMultipleSpaces": false,
          "validateWhenHidden": false,
          "key": "age",
          "attributes": {
            "size": "4"
          },
          "type": "number",
          "input": true
        },
        {
          "label": "Email Address",
          "applyMaskOn": "change",
          "tableView": true,
          "validate": {
            "required": true
          },
          "validateWhenHidden": false,
          "key": "emailAddress",
          "type": "email",
          "input": true
        },
        {
          "label": "Phone Number",
          "applyMaskOn": "change",
          "tableView": true,
          "validateWhenHidden": false,
          "key": "phoneNumber",
          "type": "phoneNumber",
          "input": true
        }
      ]
    },
    {
      "type": "button",
      "label": "Submit",
      "key": "submit",
      "disableOnInvalid": true,
      "input": true,
      "tableView": false
    }
  ],
  },
}
```


# Form Types

Understanding Web forms, Wizards, and PDF forms

Form.io offers several different options on how the form is displayed and consumed by the end-user. These different form options serve different use cases and purposes, however, the form type can be changed at any time by clicking the '**Display As**' dropdown within the Form Builder. The form type is selected when the form is created. Below are the different form options to create.

<figure><img src="/files/27bjUgn8ORIAM3MEEPSh" alt=""><figcaption></figcaption></figure>

## Web Form

A traditional web form that is typically filled out by end-users from top to bottom. To create a Web Form, click the **+New Form** button and select Web Form.

## Wizard

This form configuration allows users to progress through the form in bite-size sections instead of presenting the entire form to the user. If you are creating a form containing many fields, this is a great option to improve the user experience.

To create a Wizard, select the Webform option. While in builder mode, click the **Display As** dropdown and switch the options from Webform to Wizard.

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

The formatting will dynamically change within the builder into a Wizard-style form. The Wizard utilizes the **Panel** layout component for the Pages. When a form is switched to a Wizard, all fields will be moved into a Panel by default representing the first page of the wizard when the form is rendered.

{% hint style="info" %}
To transfer components from one Wizard Page to another, switch the Display As mode to Webform. In doing so, the Wizard Pages will separate into individual Panels where fields can be moved to and from. Switch the form back to Wizard mode to restore the previous format.
{% endhint %}

When rendered, the Wizard introduces **Cancel, Previous** and **Next** navigation buttons at the bottom of the form. The user can progress through the Wizard or use the header tabs to navigate through the form.

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

## PDF Forms

PDF-First forms allow users to upload a PDF form and add overlay fields to the form, modernizing the traditional old and clunky PDF form. For a more in-depth guide on the PDF forms please navigate to the [**following documentation**](/form-building/pdf-forms).


# PDF Forms

PDF-First forms allow users to upload a PDF form and add overlay fields to the form, modernizing the traditional old and clunky PDF form.

## Creating PDF Forms

To get started creating PDF Forms:

1. Navigate to the **Forms** section within a Project.
2. Click the **+New Form** button.

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

3. Select the **PDF Form** option

![](/files/MAEjS9Mg3JKlLU6ue7g4)

{% hint style="info" %}
A standard page size (like A4) is required to upload a PDF. Non-Standard sizes will not be accepted and will result in an error. To fix this, re-save the PDF as a file with standard page sizes.
{% endhint %}

4. Click the **Upload PDF** button. Use the file management UI to find and select any PDF on the local machine.\
   After selecting a PDF File, the platform will process and upload the PDF to the Form.io portal.

![](/files/pTjdfA1ZA5bBiCBFq3mt)

After the PDF Form is uploaded, the PDF will open inside of the Form Builder.\
Here, users can drag and drop overlay components onto the PDF. The PDF form will function like other forms within the platform. This enables form builders to incorporate PDFs into staging, team workflows, and form versioning, all while utilizing an intuitive drag-and-drop interface.

{% hint style="info" %}
Importing a PDF First Form using a Form Embed URL or a project JSON file will automatically migrate and upload the associated PDF file. There is no need to upload the PDF file after the Form JSON has been imported.
{% endhint %}

## PDF Components

Within the builder, form builders are presented with a range of overlay component choices.\
Many of these components behave the same way as they would on web forms, but certain components have been adjusted in functionality to better suit the context of PDF forms.

The list below outlines the components available and highlights the variations in settings between PDF forms and web forms. It's important to note that these changes pertain exclusively to PDF forms and do not relate to web form submissions that are downloaded as PDFs.

For documentation on the standard behavior of the available components, refer to the following documentation:

* [**Text Field**](/form-building/basic-components#text-field)
* [**HTML**](/form-building/layout-components#html-element)
* [**Email**](/form-building/advance-components#email)
* [**Text Area**](/form-building/basic-components#text-area)
* [**Number**](/form-building/basic-components#number)
* [**Phone Number**](/form-building/advance-components#phone-number)
* [**Password**](/form-building/basic-components#password)
* [**Date & Time**](/form-building/advance-components#date-and-time)
* [**Checkbox**](/form-building/basic-components#check-box)
* [**Currency**](/form-building/advance-components#currency)
* [**Select**](/form-building/basic-components#select)
* [**File**](/form-building/premium-components#file)
* [**Signature**](/form-building/premium-components#signature)

To understand how these components behave on PDF-First forms, refer to the section [#component-behavior-unique-to-pdf-forms](/form-building/form-types#component-behavior-unique-to-pdf-forms)of this document.

### **Adding Overlay Components**

Add overlay components to the PDF Form by using the drag-and-drop builder. The dropped position of the component will be the position the overlay is saved to on the PDF form. Overlay components will display their component name( E.G. texfield) within the overlay box to indicate the component type on the form.

<figure><img src="/files/0mHj8Rfnx1QsdffygKn9" alt=""><figcaption></figcaption></figure>

### **Positioning Overlay Components**

To reposition an overlay field, click and drag the field to a new position on the form. To manually resize the component, hover over the component and click and hold the blue sizing box at the bottom right of the overlay. While holding, the user can resize the height and width of the component while mainting its position.

{% hint style="info" %}
Click the + magnifying icon on the PDF form to zoom in for pixel perfect positioning when placing the overlay components. =
{% endhint %}

<figure><img src="/files/x5okWI2KeQAHUPNTkJJL" alt="" width="563"><figcaption></figcaption></figure>

### **Component Setting Changes**

The following component settings are not applied or recommended when configuring the PDF overlay settings and rendering the PDF form. These settings have the potential to interfere with form due to their dynamic characteristics and static nature of a PDF:

* Label
* Label position
* Description
* Tooltip
* Multiple value

Using any of the above component settings on a PDF-first form may result in failures, display irregularities, or unexpected behavior.

{% hint style="info" %}
Use the Placeholder setting or an HTML component as an alternative to the Label.
{% endhint %}

### Component Behavior Unique to PDF Forms

It is important to note that the following components and behaviors differ from the standard behavior on a web form.

### Input Fields

Input fields are components the end user will interact with to input data. These include:

* Text
* Email
* Text Area
* Number
* Phone number
* Password
* Date/Time

The vertical size of the component dictates the font size of the text entered by the user. To ensure you have font size unity across all of your overlay fields, use the [**PDF Overlay**](/form-building/component-settings#pdf-overlay) height setting to ensure each of your components carries the same text size and field height. Alternatively, you can use the [**PDF Font Size** ](/form-building/form-types#pdf-font-size)setting on the form to universally set all field text sizes on the form regardless of the component height.

### Checkboxes and Radios

A major component of any PDF form are checkbox or radio interface for selecting options. The PDF system incorporates the single **Checkbox** component to handle both Radio (mutually exclusive) and Checkbox interfaces. Users have the ability to style each checkbox and radio to match the uploaded PDF.

#### Checkbox

The use of a checkbox is to have a singular select capability. This is typically used for a control such as an “I agree” statement where they are providing a single yes/no answer. To add a checkbox to your form, drag and drop the Checkbox component and then resize it according to the checkbox outline as follows.

![](/files/OuZvJ0D9A4OyHLgh7Ffl)

By default, the label will be hidden for all checkbox inputs, so simply type the name of the Label for this checkbox and ensure the API key is what you would like to have saved for the data in this checkbox.

Finally, you can move and resize the checkbox to the appropriate size of the checkbox on the PDF.

![](/files/XrJZuB1ROKv83nvFWtp4)

#### Checkbox - Radio

Radio buttons are used to allow for a mutually exclusive selection between different elements on the form. A good example of this is if you wish to have a Marital status selection on your PDF form where they can toggle between “Married” or “Single” and it would deselect the one or the other as you use the control. To create a new Radio interface, you will need to drag each “radio” checkbox onto the PDF form independently. This can be done with the **Checkbox** component.

![](/files/LEcTjc07a7xwq2hfeVTj)

Once you drag and drop the Checkbox component and see the edit modal, you will then configure the Radio component by choosing the **Input Type** as **Radio**. You will then see two text boxes show up called **Radio Key** and **Radio Value**. For these, you will put the “key” of the radio that will store the data (such as “maritalStatus”) and the “value” is the value of that key when this checkbox is selected (like “married” or “single”)

![](/files/ygeiiwLKIcJii8GKQmHU)

#### Radio and Checkbox Styles

By default, the styles for the checkbox and radio buttons are a blue highlighted square. This can be customized by editing the **Custom CSS Class** on each of the checkbox components on the PDF form. The Form.io PDF Viewer utilizes a Checkbox style system called [**Pretty Checkbox**](https://lokesh-coder.github.io/pretty-checkbox/) to perform the styles. The following styles can be applied to every Radio and Checkbox component.

Here is an example of providing Custom CSS Classes to a PDF Checkbox component.

![](https://help.form.io/assets/img/userguide/pdf/checkbox10.png)

**Shape**

The following classes will alter the shape of the checkbox and radio input.

| **Class** | **Description**                                                      |
| --------- | -------------------------------------------------------------------- |
| p-round   | Turns the square checkbox into a circle (good for Radio interfaces). |
| p-curve   | Turns the square checkbox into a rounded square                      |

**Fill**

The following classes will alter the fill thickness of the input when a Checkbox / Radio is selected.

| **Class** | **Description**                                          |
| --------- | -------------------------------------------------------- |
| p-fill    | Fills up the whole checkbox with the desired color.      |
| p-thick   | Turns the outline into a thick outline with small middle |

Here is an example of these classes applied.

![](https://help.form.io/assets/img/userguide/pdf/checkbox7.png)

#### **Color**

The color of the fill can be controlled with the following classes.

| **Class** | **Description**  |
| --------- | ---------------- |
| p-primary | Blue color.      |
| p-success | Green color.     |
| p-info    | Light Blue Color |
| p-warning | Orange Color     |
| p-danger  | Red Color        |

Here is an example of colors applied.

![](https://help.form.io/assets/img/userguide/pdf/checkbox8.png)

**Type**

The type of input can also be changed to a “switch” input using the following.

| **Class** | **Description**                         |
| --------- | --------------------------------------- |
| p-switch  | Turns the checkbox into a switch input. |

The Switch has 3 different shapes you can set by adding the following class

| **Class** | **Description**                                 |
| --------- | ----------------------------------------------- |
| p-outline | Highlights switch outline when clicked          |
| p-fill    | Fills switch when clicked                       |
| p-slim    | Slims the UI and highlights switch when clicked |

<div align="left"><figure><img src="/files/mJPga4nB68oEFbFEQJqa" alt=""><figcaption></figcaption></figure></div>

In addition to the [**Pretty Checkbox**](https://lokesh-coder.github.io/pretty-checkbox/) styles, the PDF Viewer also utilizes the [**Font Awesome**](https://fontawesome.com/v4/icons/) icon library to add or change the icon displayed on the Checkbox when clicked. Add the **icon-** to the Custom CSS Field to set your class then add the icon text from the Font Awesome library.

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

Here are some common examples of icons you may want to apply using the **Font Awesome** library:

| Class          | Example                          |
| -------------- | -------------------------------- |
| icon-checkbox  | ![](/files/IPjYAa7OFhFXmVTftOK7) |
| icon-thumbs-up | ![](/files/fNVIh4CKPLONSDrkKLg8) |
| icon-edit      | ![](/files/RxfyUKd9dbhRMqZNuIVL) |
| icon-file      | ![](/files/fisUbGY8Htd7vFSZYMoq) |

{% hint style="info" %}
Use both the [**Font Awesome**](https://fontawesome.com/v3/icons/) icon library and [**Pretty Checkbox**](https://lokesh-coder.github.io/pretty-checkbox/) CSS Styling to create customized Checkbox and Radio components
{% endhint %}

#### Show checkbox/radio background setting

In [**Form Settings**](/form-building/form-types#pdf-form-settings), there is an option to show or hide the radio and checkbox component background. This setting gives checkbox and radio components a background and borders when viewing the PDF First Form submission.

## Removing a PDF

To remove a PDF from a form, Edit the form to enter the Form Builder. Click the Remove button next to the Display As dropdown and Save the form to remove the PDF. Users can then switch the PDF to a Webform by clicking the Display As dropdown and seleting Form. Although the PDF has been removed from the Form, the PDF still exists within the PDF server and will count against the allocated PDF within the license limits and will need to be removed from the [**PDF File Managment**](/form-building/form-types#pdf-file-management) section of the project.

<figure><img src="/files/x0w9bzPLjpCqwq451rgR" alt="" width="563"><figcaption></figcaption></figure>

## PDF File Management

PDF files are managed by clicking the PDF tab from the left-hand navigation bar within the Project. Here users can can see PDFs that have been uploaded to the Stage along with the PDF ID and what Form they have been uploaded and connected to. When a PDF is removed from a Form, a trash can icon will appear in the Operations column where you can remove the PDF from the project and server. This allows the user to free up

<figure><img src="/files/7jBWPbbImSee6w7RNIZn" alt=""><figcaption></figcaption></figure>

## Submitting and Viewing PDF Data

With a PDF form constructed, users can now begin to interact with submitting and viewing form data. Click the `Use` (or launch) tab to begin.

{% hint style="info" %}
The PDF Server itself does not store submission data as a part of the PDF generation process.
{% endhint %}

![](/files/MON5BXHdAN1FhG0HG5BE)

Complete the form and click `Submit` at the bottom to post the submission to the projects database.

Selecting the `Data` tab, users can view all submissions within the submission grid and can interact with individual submissions.

![](/files/YRx9lEjcU8jrp9Qz4tef)

Notice that the data displayed in the table above is overlaid on the PDF.

![](/files/OtBYAcX35JD8GYeZgRp7)

Provided the active user has permission, a printable copy of the PDF form and its data can be exported.

![](/files/aW4aQa8W2K74d4DfoUmU)

This power extends to simple form submissions as well. For example, if the traditional version of the form is filled out through an email or some other service, users can still print the submission in PDF form.

## Hybrid PDF Forms

In many cases, you may wish for your end user to submit the form as a regular webform using either the Form or Wizard display, but then print the PDF as a PDF Submission (shown above). This kind of hybrid approach is also supported by Form.io by first changing the Display of any PDF Form and then saving it as the following illustrates.

![](/files/FnuLZ0wov27G3zMS8Qfy)

Once you Save and then use this form, you will be presented with the regular webform (which is what your users will see when they fill out the form). However, there is one big difference. The original PDF is still attached to the form which lets the submission PDF generation process know that it should use the underlying PDF as a background to the data when a submission is made. This looks like the following when you print a PDF.

![](/files/rkiRaALx3IkxFCnd8vO4)

Generates the following submission PDF

![](/files/B6snmpblRbIwH4of6zVD)

This capability enables you to have the best of both worlds. Have users fill out the form as a regular webform, but print the submissions as pixel-perfect PDF output.

## Nested PDF Forms

At times, you may want to include a pre-existing PDF form into another form. Use the [**Nested Form**](/form-building/premium-components#nested-form) component inside Webforms or a page inside a Wizard form. Setting up a nested PDF Form follows the same steps and guidelines as any other Nested Form.

## Webform Submission PDFs

In addition to creating and uploading existing PDF documents, the Form.io platform can be used to generate PDFs from webform submissions. Viewing any webform submission will allow you to download the submission as a PDF by clicking the PDF download icon.

To generate a PDF, navigate to any form within your project and create a new submission. After submitting, you will be redirected to a submission view page where you can click the **PDF** icon to download the submission.

![](/files/fE4ymos2ubqDnp17SV8d)

Once the form is created, you can now create a new submission by clicking on **Use** button and then submitting the form you just created.

Clicking this icon will open the submission in a new tab where you can download or print the submission to PDF.

![](/files/LXBGsQ4L8XriNMAtj4lF)

Once you fill out the form and create a new submission, you will be redirected to a submission view page. Click the **PDF icon** at the top right of the view page to download a PDF version of the submission.

Navigate to the Data tab of any Form or Resource and view any submission to access the PDF download option.

## Page Breaks

Now that you are able to print a submission as a PDF, you may also wish to introduce page breaks into the PDF download. To accomplish this, first, edit your form, and then click on the element you wish to push down to a different page. In this example, edit the **Team Information** panel. Within the settings, introduce a special class to the element called **page-break-before**. This tells the PDF renderer where to introduce new page breaks.

![](/files/x1gzyRW94n9BPkE9YhQX)

Now make sure to save your form.

Now, you can click on the download PDF button for any of the submissions, and it will introduce a page break before the element you provided.

{% hint style="info" %}
Certain layout components like HTML and Panel will span across a page when downloading to PDF. This is intended behavior and prevents unnecessary blank space or blank pages within your PDF download. Please use the page-break-before element if a page break is needed.
{% endhint %}

![](/files/BAisYW3fpUURmU2yLHUb)

## Form.io Default Viewer

PDF downloads of basic forms submissions like Web and Wizard forms are viewed using a packaged application called Form.io Viewer. For our SaaS offering, the current viewer is hosted @ <https://formio.github.io/formio-viewer/dist/>. If you wish to make changes to the theme based on [**Bootswatch Themes**](https://bootswatch.com/3/), then you can use the following format

{% hint style="info" %}
Submission PDF downloads for PDF First forms do **not** utilize the formio-viewer, but instead, utilize the formio-pdf module for downloading PDFs for PDF-first forms.
{% endhint %}

```
https://formio.github.io/formio-viewer/dist/?theme=paper
```

Like so…

![](/files/lCZPPlGaBt5YPgHLWIJq)

You can also change the theme using the **PDF Theme** to select an available [Bootswatch](https://bootswatch.com/) theme in the **PDF Settings** section:

![](/files/csyNicQYAaFGw04ocOnk)

Bootswatch themes are provided by a third party. They may be updated to match ongoing Bootstrap development. To continue using a fixed version of Bootswatch and avoid potential styling changes, consider implementing a [#custom-pdf-viewer](/form-building/form-types#custom-pdf-viewer) that uses a fixed version.

### Viewer Parameters

There are also some parameters that you can pass to the viewer that is hosted by Form.io for the SaaS offering to alter the output of the generated PDF. These parameters can be provided a GET query parameters to the viewer. For example, to not show the header for the viewer, you can provide the following.

```
https://formio.github.io/formio-viewer/dist/?theme=paper&header=0
```

The following viewer parameters are supported.

| Setting | Description                                   | Example    |
| ------- | --------------------------------------------- | ---------- |
| theme   | The Bootswatch 3 theme to provide to the pdf. | theme=yeti |
| header  | If you wish to hide the header                | header=0   |

### PDF Generation Parameters

In addition to there being viewer parameters, there are also parameters that you can provide to the end of the PDF generation API. For example, to alter the margins of the generated PDF document, you can provide the following to the PDF generation url.

```
https://forms.mysite.com/myproject/yourform/submission/[SUBMISSION_ID]/download?token=TOKEN&margin=20,20,20,20
```

The accepted PDF parameters are listed in the table below.

| Setting | Description                                                      | Example            |
| ------- | ---------------------------------------------------------------- | ------------------ |
| margin  | The margin as provided like a CSS margin (top,left,bottom,right) | margin=20,20,20,20 |
| scale   | The scale to provide to the generated PDF                        | scale=0.6          |
| width   | The width of the viewport when generating the PDF                | width=800          |
| height  | The height of the viewport when generating the PDF               | height=1100        |
| view    | To show the submission in “viewAsHtml” mode                      | view=1             |

### **Custom PDF Viewer**

By default, the submission PDFs that are generated use a default Form viewer application to render the submissions. For the SaaS offering, this is the hosted viewer described above. For Self Hosted Deployments, this Viewer Application is packaged within the formio-enterprise container and resides in your own self-hosted environment.

To satisfy custom requirements, a **Custom PDF Viewer** application can be used, by modifying the default, to render the submissions for PDF generation. This is very helpful to provide custom PDF templates, or maybe even create submissions PDFs that introduce custom elements into the PDF generation. To achieve this, start by forking the Default Form Viewer found @

[**https://github.com/formio/formio-viewer**](https://github.com/formio/formio-viewer)

Once you download this Viewer application, make sure you install dependencies with the following command:

```
npm install
```

Now, make any modifications needed to the application. For example, the [**Paper Theme**](https://bootswatch.com/3/paper/) from Bootswatch can be used by the Viewer by making the following change to the `src/index.html`

**src/index.html**

```
document.write('<link rel="stylesheet" href="lib/bootswatch/paper/bootstrap.min.css" />');
```

You can now compile this application using the following command.

```
npm run build
```

This will create a **dist** folder, which must then be launched to your own hosting service. Once this is hosted, form settings can be edited. Then, introduce a new **Custom Property** called **viewer** and set the value to the URL of the custom viewer application as seen below.

Please [**Click Here**](/deploy/pdf-server) for more information

![Using a 'key - value' approach](/files/cXg6XR4dOcGYLp8ypKGX)

Another way to configure the PDF viewer is by using a **PDF Viewer URL** field in the **PDF Settings** section.

![Using 'PDF Viewer URL' field](/files/oY299BVL7hbkLrNorVAp)

Once you save, and then go back to submission and download that submission, you will notice that the PDF download now uses your own custom viewer application to render the submission PDF.

![](https://help.form.io/assets/img/userguide/pdf/custom-viewer-download.png)

To make all PDFs generated by a deployed PDF server use this customized Viewer Application, set the Environment Variable `FORMIO_VIEWER` within your Docker container run command.

```
docker run -itd \
  -e "FORMIO_SERVER=https://formio.yourdomain.com" \
  -e "FORMIO_PROJECT=59b7b78367d7fa2312a57979" \
  -e "FORMIO_PROJECT_TOKEN=wi83DYHAieyt1MYRsTYA289MR9UIjM" \
  -e "FORMIO_PDF_PROJECT=https://formio.yourdomain.com/yourproject" \
  -e "FORMIO_PDF_APIKEY=is8w9ZRiW8I2TEioY39SJVWeIsO925" \
  -e "FORMIO_VIEWER=https://formio.github.io/formio-viewer/dist/?theme=paper" \
  -e "FORMIO_S3_KEY=[S3 KEY]" \
  -e "FORMIO_S3_SECRET=[S3 SECRET]" \
  -e "FORMIO_S3_BUCKET=[S3 BUCKET]" \
  -e "FORMIO_S3_REGION=[S3 REGION]" \
  --restart unless-stopped \
  --name formio-files-core \
  -p 80:4005 \
  formio/formio-files-core;
```

Please [**Click Here**](/deploy/pdf-server) for more information.

### Mounting Custom PDF Viewer onto PDF Server

The fastest way to get your PDF Viewer onto your local deployment is to mount it onto the PDF server container. You will be using [bind mounts](https://docs.docker.com/engine/storage/bind-mounts/) to replace PDF servers form-viewer with your custom form-viewer. To get started open up your project containing your `docker-compose.yml` file used to run your local deployment. Your file structure should look something like the following

```
local
   |- /conf.d
      |- default.conf
   |- /data
      |- /db
      |- /minio
      |- .env
   |- docker-compose.yml
```

Add a new directory to your `local project` called /viewer and copy the files within your `formio-viewer project` /dist folder to the /viewer folder.

<figure><img src="/files/94viaN7FsLrKahwssq7K" alt=""><figcaption></figcaption></figure>

```
local
   |- /conf.d
      |- default.conf
   |- /data
      |- /db
      |- /minio
      |- .env
 + |- /viewer
 +    |- /assets
 +    |- /fonts
 +    |- /lib
 +    |- index.html
   |- docker-compose.yml
```

Now that your pdf viewer files are within your local deployment project you need to mount the files within the PDF server container file system. To do this open up your docker-compose.yml and add the following

```
  ...
  pdf-server:
    image: formio/pdf-server
    restart: no
    mem_limit: 2048m
    links:
      - mongo
      - minio
    ports:
      - "4005:4005"
    environment:
      MONGO: mongodb://mongo:27017/formio
      FORMIO_S3_SERVER: minio
      FORMIO_S3_PORT: 9000
      FORMIO_S3_BUCKET: formio
      FORMIO_S3_KEY: CHANGEME
      FORMIO_S3_SECRET: CHANGEME
      FORMIO_PDF_PORT: 4005
    env_file:
      - data/.env
    volumes:
+     - "./viewer:/src/node_modules/@formio/viewer/dist"
  ...
```

`"- "./viewer:/src/node_modules/@formio/viewer/dist"` takes the files in /viewer on your host machine and adds them to your containers file system under the path `/src/node_modules/@formio/viewer/dist`

Run the command `docker compose up -d` and try downloading a PDF submission. You should now see the pdf being rendered with your custom formio-viewer<br>

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

### Formio-Viewer Repository

The [formio-viewer](https://github.com/formio/formio-viewer/) repository is where you will design and build your own custom pdf viewer. Fundamentally, the purpose of the formio-viewer is to...

* Replace formio components with custom components
* Add custom css to index.html
* Call the window\.setForm function to create a new form and then set the submission of that form in index.html

When these tasks are done the PDF server will then convert your index.html to a PDF

#### Replacing formio components

To replace formio components with your own custom components navigate to the `/src/components/` directory. This directory is where you will override and add new functionality to existing formio components. In this example you will be overriding the edit grid behavior to expand its view to show all the components nested within. Start by creating a new javascript file in the /components directory called ViewerEditGrid.js and add the following code

**Note:** It is the convention when replacing components to prefix the replaced component with `Viewer`

```
import EditGridComponent from "@formio/js/components/editgrid/EditGrid";

export default class ViewerEditGrid extends EditGridComponent {
    constructor(...args) {
        super(...args);
        // Disable edit grid header rendering.
        this.component.templates.header  = ""
        // If we do not have a submission, add an initial row to all EditGrids
        if (this.root && !this.root.submissionSet) {
            this.component.openWhenEmpty = true;
        }
    }

    // Ensure all rows open.
    isOpen() {
        return true;
    }
}
```

[Click here](/dev/custom-components) to learn more about creating custom components

Now you need to replace the edit grid component with the new viewer edit grid. Open the src/renderer.js file and add the following code

```
import {Formio} from '@formio/js/formio.form.js';
import Flatpickr from 'flatpickr';

window.flatpickr = window['flatpickr-css'] = Flatpickr;
import './components/ViewerCalendar';
import ViewerDateTime from './components/DateTime';
import ViewerTextField from './components/TextField';
+ import ViewerEditGrid from "./components/ViewerEditGrid";

Formio.Components.setComponent('datetime', ViewerDateTime);
Formio.Components.setComponent('textfield', ViewerTextField);
+ Formio.Components.setComponent('editgrid', ViewerEditGrid)
export {Formio};
```

`Formio.Components.setComponent('editgrid', ViewerEditGrid)` sets the edit grid component to the new viewer edit grid component. Now all edit grid components will be expanded and have the header removed when rendering onto a pdf

#### Adding custom css

To add custom css to your pdf viewer make changes within the \<style>\</style> tag in the `index.html` file. For example, if you wanted to change the background of your pdf make the following changes within the \<style> tag

```
    ...
    body {
        background-color: #00ffab;
    }
</style>
```

You can also do this by adding a CSS file in your `/src/assets` directory.

#### window\.setForm(form, submission, options) function

In `index.html` there is a vital function for converting your form submissions into pdfs called `window.setForm`. This functions job is to create a new form on the page with the `form` and `options` arguments and then set the forms instance to the `submission` argument. This function is called when you go to download your pdf and is key to understanding how your forms will be rendered in your pdf downloads. You do not need to make any changes to this function

#### Building your source code to distribution code

To build your source code there is a script called `build` in the `package.json` file in your project. Run this command by typing `npm run build` in your terminal. This will do the following...

* `gulp build` grabs the necessary CSS, JavaScript, Bootstrap, Formio.js library, etc. needed to render the form submission onto the page and puts them into the /dist directory
* `webpack --config webpack.config.js` will build the `renderer.js` file to /dist/lib/formiojs/formio.form.min.js, bundling all the necessary javascript needed to replace components with viewer components
* `gulp inlinesource` replaces all \<script src="..." inline> and \<link href="..." inline> with their inline source. For example

```
//index.js
function foo(){
  return 1
}

//index.html
<html>
<script src="index.js" inline></script>
</html>

// After gulp inlinesource
<html>
<script>function foo(){return 1}</script>
</html>
```

After building your source code you can now use the index.html file to generate PDF submissions from your forms. See this for how to do this

## PDF Form Settings

The PDF Form Settings allow the user to change various UI and theming elements for PDF First Forms and PDF submission downloads. Access Form Settings and scroll down to the PDF Settings section to utilize the following configurations.

#### PDF Theme

Select a [**Bootstrap Theme**](https://bootswatch.com/) to change the CSS styling of the PDF Submission downloads.

#### **Printed PDF Page Size**

Change the PDF dimensions by selecting a page size for the rendered PDF First Form. Read more on [**PDF Page Size**](https://www.prepressure.com/library/paper-size)

#### **PDF Font Size**

By default, the PDF's font size is determined by the vertical size of the PDF overlay field. Select a font size to globally set the field font size for the PDF First Form regardless of the field overlay size.

#### **PDF Margins**

Set the Margin size of the rendered PDF First Form using the same margin guidelines for CSS attributes.

#### **Hide Title Bar**

Hides the form title when viewing a Submission PDF download.

#### **View As Plain Text**

Check this if you would like to render the Submission PDF as plain text view. This setting will hide the field UI and only show the submitted text when viewing the download.

#### **Use Condensed Mode**

Check this if you would like your Submission PDF downloads to render with Condensed mode enable&#x64;**.** This setting will minimize field margins and padding as well as default the font size to 11pt. Field UI is replaced with an underline instead of the full box border.

#### Show checkbox/radio background

Check this if you would like checkbox and radio components that are not checked or ticked to have background and borders when viewing the PDF First Form submission.

#### Show Change Log

Activates the [**Submission Revision**](/form-building/form-revisions#enable-form-versioning) change log. PDF submission downloads will now display all Submission Revision information for the submission being viewed.

## PDF Form Templates

Apply your own templates to the PDF forms Header or Footer.

#### Header & Footer Template

Inject HTML as a **header/footer** for every page of the generated PDF. The Template should be valid HTML markup with the following classes used to inject printing values into them:

* `date` - Formatted print date
* `pageNumber` - Current page number
* `totalPages` - Total amount of pages

Use Base64 for images.

The following variables and functions are available inside templates:

* `submission` - The complete submission object.
* `form` - The complete form JSON object.
* `formatDate(dateFormat, timezone, date)` - The function that customizes the date display format. Use the moment supported date format and time zone. The date is equal to the submission creation date by default.

**Example:**

```
<div style="margin-left:15px;">
  <p>
    Form {{ form._id }} ("{{ form.title }}"). 
    Submission {{ submission._id }},
    created {{ formatDate("MM-dd-yyyy", submission.metadata.timezone) }},
    modified {{ formatDate("MM-dd-yyyy", submission.metadata.timezone, submission.modified) }}.
  </p>
  <p>
    Printed on <b class="date"></b>. 
    Page <b class="pageNumber"></b> of <b class="totalPages"></b>
  </p>
</div>
```


# Dynamic PDF Translation

| Server     | Minimum Version |
| ---------- | --------------- |
| API Server | 9.8.0           |
| PDF Server | 5.14.0          |

## Overview

Dynamic PDF Translation allows form submission PDFs to be downloaded with field labels, placeholders, and descriptive text automatically translated into a target language. Translation is driven by a remotely hosted JSON file and activated through a URL query parameter at download time—without requiring the form to be resubmitted.

When a user downloads a PDF for a form submission, they can append a language parameter to the download URL. The PDF server fetches translations from a configured endpoint and replaces matching field text before rendering the PDF.

Changing the language parameter value changes the rendered PDF language immediately, allowing the same submission to be downloaded in multiple languages without modifying the form or submission data.

The Translations URL can be configured in two ways:

* **Per form** — via the PDF Settings panel in Form Settings, using the Translations URL field. This applies translation to a single form only.
* **Globally** across all forms in a project — via the Project Settings. When set, the global Translations URL applies to every form in the project that does not have a form-level override.

{% hint style="info" %}
Global project-level translation is not yet available and will be released in a future update.
{% endhint %}

## How It Works

When a translated PDF is requested:

1. The PDF server reads the language query parameter from the PDF download URL.
2. It fetches the translation JSON from the configured Translations URL.
3. It looks up matching text values for the selected language code.
4. Matching field labels, placeholders, and descriptions are replaced with translated values.
5. The PDF is rendered and returned in the selected language.

If no translation is found for a text string, the PDF server falls back to the original text defined in the form.

## Prerequisites

Before using Dynamic PDF Translation, ensure you have:

* The appropriate API Server (9.8.0+) and PDF Server (5.14.0+) versions are deployed in your environment
* A publicly accessible URL hosting a valid translations JSON file (see format below)

## Supported Translation Scope

Dynamic PDF Translation applies to text defined in the form. It does not translate submitted user-entered values — submission data remains unchanged and is rendered exactly as entered.

The following form field settings are supported for translation:

<table><thead><tr><th width="266.800048828125">Component Setting</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/RMPSmrLsLf42vdeQTxEI#label">Label</a></td><td>The field label displayed above or beside the input field</td></tr><tr><td><a href="/pages/RMPSmrLsLf42vdeQTxEI#description">Description</a></td><td>Help text displayed below the field</td></tr><tr><td><a href="/pages/RMPSmrLsLf42vdeQTxEI#prefix">Prefix / Suffix</a></td><td>Text displayed before or after the input value</td></tr><tr><td>Static Text</td><td>Rendered text output from <a href="/pages/qNtJyQlSL6VEVaytfJrT#html-element">HTML </a>and <a href="/pages/qNtJyQlSL6VEVaytfJrT#content">Content </a>components</td></tr></tbody></table>

## Setup & Usage

### 1. Prepare the translations JSON file

Create a **JSON file** following the format described below, with a key for each language code and entries for every string in your form that requires translation.

{% hint style="info" %}
The field names below are examples only. The keys in each language object must exactly match the text used in your own form — labels, static text, and descriptions will vary depending on how your form is built.
{% endhint %}

```json
{
  "ru": {
    "User Information": "Информация о пользователе",
    "First Name": "Имя",
    "Last Name / Surname": "Фамилия",
    "Date of Birth": "Дата рождения",
    "Email": "Электронная почта",
    "Address": "Адрес"
  },
  "es": {
    "User Information": "Información del usuario",
    "First Name": "Nombre",
    "Last Name / Surname": "Apellido",
    "Date of Birth": "Fecha de nacimiento",
    "Email": "Correo electrónico",
    "Address": "Dirección"
  },
  "zh": {
    "User Information": "用户信息",
    "First Name": "名",
    "Last Name / Surname": "姓",
    "Date of Birth": "出生日期",
    "Email": "电子邮件",
    "Address": "地址"
  }
}
```

### 2. Host the Translation File

**Host a JSON endpoint** and paste in your translations payload. Copy the URL of the hosted endpoint to utilize in the next step.

`https://myapi.example.com/v1/translations`

{% hint style="info" %}
The endpoint must be publicly accessible and return a valid Content-Type: application/json response.
{% endhint %}

### 3. Configure the Translations URL

Within your Form.io Project, **open the form** you want to enable translation for.

Click the **Form Settings tab** and locate the PDF Settings section.

<figure><img src="/files/5zwfyPD82eSLR8hFMZ4x" alt=""><figcaption></figcaption></figure>

Navigate to the **PDF Settings** section and paste the hosted endpoint URL in the **Translation URL** setting field.

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

**Save** the form settings.

### 4. Test PDF Translation

To test the PDF Translation manually, make a submission using your form and **download** the submission as a **PDF**.

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

In the browser, append the **language query parameter** `&language=example` to the PDF download URL:

```
https://your-server/form/<id>/submission/<id>/download&language=es
```

{% hint style="info" %}
Only text strings that exist as keys in the translations JSON will be translated. Text not found in the JSON remains in its original language.
{% endhint %}

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

### 5. Switching Languages

Each PDF download request is stateless. Passing a different `language` parameter value generates a new PDF in the selected language. No changes to the form or submission are required.

`https://your-server/submission/<id>/download&language=ru`\
`https://your-server/submission/<id>/download&language=zh`

{% hint style="info" %}
In production, switching languages would typically be handled by the application — for example, re-triggering the PDF download request with an updated language value when the user changes their language selection.
{% endhint %}

## Troubleshooting

<table><thead><tr><th width="191.800048828125">Symptom</th><th width="234.5999755859375">Likely Cause</th><th>Resolution</th></tr></thead><tbody><tr><td>PDF downloads in original language despite parameter</td><td>Translations URL not saved, or endpoint inaccessible</td><td>Verify the URL is saved in Form Settings and returns valid JSON when opened in a browser</td></tr><tr><td>Some fields are not translated</td><td>Field text does not exactly match a key in the JSON</td><td>Check for typos, trailing spaces, or capitalization differences between the form text and JSON keys</td></tr><tr><td>Unsupported language code used</td><td>Language code not present in the JSON file</td><td>Add the missing language block to the JSON file and re-save the endpoint</td></tr><tr><td>PDF server returns an error on download</td><td>JSON endpoint unavailable or returning invalid content</td><td>Confirm the endpoint is active, publicly accessible, and returning valid JSON</td></tr></tbody></table>


# PDF Basic vs PDF Plus

The Form.io Platform handles PDF forms through additional PDF offerings that are licensed separately from Form.io Enterprise.

The Form.io PDF Solution is a powerful tool with two options: **PDF Basic** and **PDF Plus**.\
Explore each option to identify which one aligns most effectively with your specific requirements.

{% hint style="info" %}
Contact <support@form.io> for more information about the PDF offerings
{% endhint %}

### PDF Basic

PDF Basic enables the ability to print and download webform submissions as a PDF output. This feature is available on the SaaS offering ([portal.form.io](http://portal.form.io)) or the PDF Basic add-on for self-hosted deployments through the containerized [PDF Server](/deploy/pdf-server).

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

### PDF Plus

PDF Plus enables PDF-First forms, where an interactive form is built overlaid on a pixel-perfect PDF background.\
Additional PDF Plus features include:

* PDF Template Designer
* PDF Conversion

PDF Plus is available on the SaaS offering ([portal.form.io](http://portal.form.io)) with a subscription, or on Self-Hosted configurations that license PDF Plus.

#### PDF Template Designer

Design the output of PDF downloads of your webform submissions. These template designs can take the data from your webforms and output the data into a customized PDF for things like receipts, mailers, contracts, quotes, etc.

[**Template Designer Documentation**](#pdf-template-designer)

#### **Dynamic PDF Translation**

The PDF server supports dynamic translation of field labels, static text, and descriptions at download time via a `language` URL parameter. Read the full setup instructions and configuration guide below for more detail.

[**Dynamic PDF Translation Documentation**](/form-building/pdf-forms/dynamic-pdf-translation)

#### **Digital PDF Forms (PDF-First forms)**

Convert traditional PDFs to JSON-driven webforms with pixel-perfect backgrounds by adding digital components on top of the PDF background.

#### **PDF Conversion**

The PDF Plus offering also enables the auto-conversion of Digital PDF Forms in two capacities:

* **Fillable PDF Form:** If a PDF has existing XML data and fields on the form in a standard format, the fields will be converted to a JSON Form.io form.
* **Non-Fillable PDF Form:** If a PDF is a flat document and a standard PDF format, and AWS Textract is integrated with the self-hosted Form.io Developer Portal application, the fields on the form will be sensed by the Textract library, converted to JSON form fields, inclusive of exact placement and labels.

{% hint style="info" %}
***Non-fillable PDF Forms are not available on SaaS (portal.form.io). This is only available with a Self-Hosted configuration that includes an additional AWS Textract integration.***
{% endhint %}


# PDF Template Designer

## What Is The PDF Template Designer

The PDF Template Designer allows form builders to design and format the PDF output of webform submissions, while maintaining the original webform layout and structure end-users fill out.

{% hint style="info" %}
Contact <sales@form.io> for more information on the PDF Template Designer
{% endhint %}

{% embed url="<https://www.loom.com/share/1910e04094d24dc2b5eef6bd25a9d8e3>" %}

## Why Should I Use The PDF Template Designer

A direct one-to-one output of the submission data is not always the desired outcome when downloading webform submission to a PDF output. At times, this data output is required to be specifically formatted to meet certain requirements. Utilize the PDF Template Designer to support these requirements, such as formatting submission data into customized receipts, contracts, mailers, reports, etc...

## How To Use The PDF Template Designer

The PDF Designer is an add-on for the Enterprise self-hosted deployment included with the [**PDF Plus offering**](/deploy/pdf-solution#pdf-plus). Once enabled, a PDF icon will appear within the form header, in between the *Data* and *Actions* tab.

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

Entering the PDF Template Designer mode will direct the user to a special builder where the PDF Template can be configured and designed. Although it resembles the builder seen in Form edit mode, the PDF Template builder is limited and determines which webform component data should be included and the layout of that data within the PDF submission output.

Within the builder, all Form.io [**Layout Components**](/form-building/layout-components) are available to organize and arrange the submission data within the PDF output download. The **Existing Fields** tab lists all components within the webform that can be added to the PDF Template Designer. Submission data of these Existing Fields will be included within the PDF output download.

{% hint style="info" %}
Use **Search field(s)** to quickly find components you wish to include within the PDF output.
{% endhint %}

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

Use the **Clear PDF Form** button to quickly start from scratch with a new design. Click the **Reset All Components** button to restore all components to their original state in the Webform.

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

## Tutorial

This example will demonstrate creating a PDF Template originating from a large webform containing a multitude of fields. The PDF Template will take several key fields from the form to generate a general summary of the webform.

**Prerequisite**\
Create a webform with submission data. This example is using a Worker Compensation Application with a large number of fields.

1. Click the **PDF** tab within the Form header of the webform to navigate to the PDF Designer.
2. Click the **Clear PDF Form** to start PDF Template Designer from a blank slate

<figure><img src="/files/2cMGK3B2dnqRHCTnWmjk" alt=""><figcaption></figcaption></figure>

3. Add **Layout** components to organize fields that will be included in the PDF output

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

4. Click the **Existing Fields** and add fields from the webform that should be included in the PDF output.

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

5. View a submission within the **Data** tab of the webform

<figure><img src="/files/4CF5X3BihZFb5VIRuD9l" alt=""><figcaption></figcaption></figure>

6. Click the **PDF Icon** when viewing the submission

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


# Form Builder

Understanding the Form Builder UI

Before we get into Form Building, it's important to understand the different UI elements of the builder. You will be directed to the Form Builder when creating a Form or Resource, or when clicking the Edit button for an existing Form or Resource.

Before creating your first form, take some time to review the settings and operations found in the Form Builder.

{% embed url="<https://youtu.be/KxhfLIfwfIA>" %}

## **Builder Settings**

The following settings can be found in the UI of the Form Builder when editing a Form.

### **Edit**

Click the Edit button for a specific Form or Resource to enter builder mode.

### **Display As**

Change the way the form is displayed by selecting an option from the Display As dropdown. Forms can be displayed as a Wizard, PDF, or traditional Web Form. The form display type can be changed dynamically, even when the form is live!

### **Search Field**

Find the field you're looking for by quickly using the component search bar

### **Component Grouping**

Components are grouped into different tabs based on the component type. The component groupings are [**Basic**](/form-building/basic-components), [**Advanced**](/form-building/advance-components), [**Layout**](/form-building/layout-components), [**Data**](/form-building/data-components), [**Premium**](/form-building/premium-components)**,** and [**Existing Resource Fields**](/form-building/resources-readme/existing-resource-fields)

### **Drop Zone**

Drag and drop your components onto the drop zone indicated by the blue box.

### **Copy Form**

Click the Copy Form button to copy the form JSON and components to a new form.

### **Cancel**

Cancel all changes made from the last time the form was saved. Canceling a form with unsaved changes will prompt a confirmation window before confirming the Cancel.

### **Save Form**

Save the Form in its current state.

### Visual Tour

{% embed url="<https://view.genially.com/632485c3b59ced00107a389e>" %}
Visual guide to the Form Builder.
{% endembed %}

## Inline Component Settings

When a Component is added and saved to the builder, there will be inline settings for the component when hovering over the field found at the top right, above the field. These settings are not component specific and will be available for every component added to the builder

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

### **Edit**

Opens the settings window for the component.

### **Move**

Reposition the component on the form by clicking and holding the Move icon

### **Edit JSON**

Directly edit the component settings by configuring the JSON directly. The JSON Schema will grow as settings are configured within the component setting UI window. Check the `Full Schema` setting to view the full schema configurations to display the setting schema that is not currently configured for the component.

{% hint style="info" %}
Copy and paste the JSON schema of one component to easily implement those settings for other components within another stage or project.

[**Click here for a full list of Component JSON Schema**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endhint %}

### Copy

Copies the component JSON. When the Copy button is selected the Paste button will appear within the Inline Component Settings.

### **Paste**

Pastes the component that was previously copied. The new component will be added directly below the component where the Paste button was clicked.

### **Delete**

Deletes the component from the form. If a component is removed unintentionally, refresh the form to its previous state by navigating away from the form and selecting **No** for the Save prompt, or reloading the browser directly.


# Form Settings

Form Settings allow you to further modify and configure your form. From basic functionality like renaming your form, to more advanced features like writing custom scripts to change the Form behavior using Form Controllers. To access the settings, click the 3 dot icon in the Form's header to view and configure Form's settings.

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

{% hint style="info" %}
[**Click Here**](/admin/projects/project-settings#form-defaults) for information about configuring default settings for your Forms and Resources
{% endhint %}

### Form Settings

**Title:** The title the end-user will see when filling out the form. The Title is how you will identify the form within your project.

**Name:** This is the machine name for your Form. It can only contain alphanumeric characters and will automatically populate from the title you enter in **camelCase**. Form Names can be independently changed if you do not wish to carry the Title.

The Form Name is utilized when embedding the Form into your application.

**API Path:** The API Path is the endpoint for accessing the Form and Form submissions. The API path name, like the Form name, will auto-populate based on the Title but can also be changed independently.

**Custom Action URL:** Set an endpoint the form will hit after a submission is made to execute a custom action.

**Form Tag**: Add a tag(s) to the form. Tags can be beneficial for organizing Forms and Resources within your project or utilizing the tag for custom functionality within your application. Forms and Resources can be filtered based on their tag.

**Disable Autocomplete:** Disable your fields from auto-populating data based on your browser cache.

**Wizard Header:** Configure how Wizard pages will display

### PDF Settings

The PDF Form Settings allow the user to change various UI and theming elements for PDF First Forms and PDF submission downloads. Access Form Settings and scroll down to the PDF Settings section to utilize the following configurations.

Please navigate to [**PDF Form Guide**](/form-building/pdf-forms#pdf-form-settings) to read more on the available PDF Form settings.

### Form Controller

The Form Controller is a powerful concept of Form.io which gives control of the rendered form using JavaScript. The Form Controller can do almost limitless things in the context of the renderer, allowing users to change Wizard Headers, implement a Thank You Page, and execute complex logic and workflows.

Please [**Click Here**](/dev/form-development/form-renderer#log-change-events) for examples of the Form Controller in action.

### Submission Collection

Modify the database collection that stores all of the submissions within the form. This allows the selection of certain fields as **indexes** for significant performance improvements. The Submission Collection feature is part of the [**Security Module**](/dev/the-security-module#submission-collections) suite. Visit the link or contact <sales@form.io> for more information.

### **Form Deployment MachineName**

The Machine Name connects the form to the project through import/export or deployments.

{% hint style="danger" %}
Tampering with the Form machineName can break Project imports and exports. Do not modify unless you know what you're doing.
{% endhint %}


# Basic Components

Using and configuring Basic Components in the Form Builder

Basic components are found at the top of the component groupings within the Form Builder. These components are more commonly used on traditional web forms and should be familiar components to anyone who has built a form in the past. Information for each of the Basic Components like unique settings, JSON code, and field examples is provided below.

{% embed url="<https://youtu.be/ezh-82kQAJc>" %}

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Text Field</strong></td><td>Used for short and general text input</td><td></td><td><a href="#text-field">#text-field</a></td></tr><tr><td><strong>Text Area</strong></td><td>A multi-line input field that allows for longer text</td><td></td><td><a href="#text-area">#text-area</a></td></tr><tr><td><strong>Number</strong></td><td>Input field limited to number type values</td><td></td><td><a href="#number">#number</a></td></tr><tr><td><strong>Password</strong></td><td>An input field with HTML type set to Password</td><td></td><td><a href="#password">#password</a></td></tr><tr><td><strong>Checkbox</strong></td><td>A boolean checkbox</td><td></td><td><a href="#check-box">#check-box</a></td></tr><tr><td><strong>Select Box</strong></td><td>A multi-option checkbox</td><td></td><td><a href="#select-box">#select-box</a></td></tr><tr><td><strong>Select</strong></td><td>Selectable values presented in a dropdown</td><td></td><td><a href="#select">#select</a></td></tr><tr><td><strong>Radio</strong></td><td>Select a single option from a list of options</td><td></td><td><a href="#radio">#radio</a></td></tr><tr><td><strong>Button</strong></td><td>Buttons perform various actions within the form</td><td></td><td><a href="#button">#button</a></td></tr></tbody></table>

### Text Field

A Text Field can be used for short and general text input. There are options to define input masks and validations, allowing users to structure information into desired formats. Additionally, this component can be converted into a string-based date/time picker.

{% tabs %}
{% tab title="Unique Settings" %}
**Widget:**\
The widget is the display UI used to input the value of the field. By default, the widget will be set to a traditional Input Field, however, you can change the widget to turn the text field into a calendar picker.

![](/files/-MdH90sm-iqc0TYmfuDp)

When set, the Textfield is converted to a string-based Calendar Widget. This component stores dates as plain strings, meaning the saved values remain fixed and do **not** adjust based on the user's location or timezone.

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

**Widget Settings:**\
When the Calendar Picker setting is selected, a new code block appears within the component settings that allows the user to customize the widget by editing its JSON configuration.

<pre><code>{
  "<a data-footnote-ref href="#user-content-fn-1">type</a>": "calendar",
  "altInput": true,
  "<a data-footnote-ref href="#user-content-fn-2">allowInput</a>": true,
  "<a data-footnote-ref href="#user-content-fn-3">clickOpens</a>": true,
  "<a data-footnote-ref href="#user-content-fn-4">enableDate</a>": true,
  "<a data-footnote-ref href="#user-content-fn-5">enableTime</a>": true,
  "mode": "single",
  "<a data-footnote-ref href="#user-content-fn-6">noCalendar</a>": false,
  "<a data-footnote-ref href="#user-content-fn-7">format</a>": "yyyy-MM-dd hh:mm a",
  "<a data-footnote-ref href="#user-content-fn-8">dateFormat</a>": "yyyy-MM-ddTHH:mm:ssZ",
  "useLocaleSettings": false,
  "<a data-footnote-ref href="#user-content-fn-9">hourIncrement</a>": 1,
  "<a data-footnote-ref href="#user-content-fn-10">minuteIncrement</a>": 5,
  "<a data-footnote-ref href="#user-content-fn-11">time_24hr</a>": false,
  "saveAs": "date",
  "displayInTimezone": "",
  "timezone": "",
  "disable": [],
  "<a data-footnote-ref href="#user-content-fn-12">minDate</a>": "",
  "<a data-footnote-ref href="#user-content-fn-12">maxDate</a>": ""
}
</code></pre>

***

**Input Mask:** Use an Input Mask when a specific input format is needed. This is useful for enforcing formats like phone numbers, postal codes, SSN, etc.

**Display Mask:** A display mask helps to display the input in a readable way, this won't affect the value which will be saved (to affect both view and saved value, delete Display Mask and use Input Mask).

*Mask Examples*

9: numeric\
a: alphabetical\
\*: alphanumeric\
\
Example a Phone Number mask: (999) 999-9999\
\
See the [**jquery.inputmask documentation**](https://github.com/RobinHerbots/Inputmask) for more information.

**Apply Mask On:** Determines when this component should trigger the configured mask. Defaults to *Change.*

*Change* - Validation will actively trigger any time there is a change in the field. This is the default option for every field.

*Blur* - Validation will only trigger when the field is no longer focused.

**Input Mask Placeholder Char:** Specify a character to be used as a placeholder in the field.\
\
E.g., ˍ

Placeholder char will be replaced by a space if it is used inside the mask

**Allow Multiple Masks:** Check this setting if the field should allow the end-user to select a mask from a dropdown menu.

Once selected, a grid will appear where you can add a label and corresponding input mask. Click the '+ Add Another' button to add a new Input Mask.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/eYjrpeL>" %}
{% endtab %}

{% tab title="Guidance" %}
**When should I use the Text Field component?**

* **Unpredictable or freeform responses.** If you can’t reasonably predict a user’s answer to a prompt and there might be wide variability in users’ answers.
* **Input simplicity.** When using another type of input will make answering more difficult. For example, birthdays and other known dates are easier to type in than they are to select from a [**date picker**](https://designsystem.digital.gov/components/date-picker/)**.**
* **Pasted content.** When users want to be able to paste in a response.
  {% endtab %}

{% tab title="JSON" %}
{% code overflow="wrap" %}

```
{
  "label": "Text Field",
  "disableSortingAndFiltering": false,
  "tableView": true,
  "key": "textField",
  "type": "textfield",
  "input": true
}
```

{% endcode %}

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Text Area

A Text Area is a multi-line input field that allows for longer text. The Text Area can also be converted to WYSIWYG content editor.

{% tabs %}
{% tab title="Unique Settings" %}
**Rows**: Controls how many default rows are set in the Text Area

**Editor:** This option will convert the text area into one of the following WYSIWYG Editors:\
\&#xNAN;*Note: Rich text editors may affect the accessibility of forms that use them.*

* [**Ace**](https://ace.c9.io/)
* [**CKEditor**](https://ckeditor.com/)
* [**Quill**](https://quilljs.com/)

*Enable Image Upload* - Check this setting to allow image uploads to the WYSIWYG editor.

*Image Upload Storage* - Select the Storage provided integrated within the Project.

**Save As** - This setting determines how the value should be entered and stored in the database:

* *String*
* *JSON*
* *HTML*

**Auto Expand:** The Text Area will automatically expand vertically as the user types into the field.

**Enable Image Upload:** Allows the user to upload an image to the WYSIWG Editor

**Editor Settings:** The following documenation will allow you tooverride the code base of the WYSIWYG Editor, customizing the UI and functionality specific to your needs.

[**Override CKEditor**](/how/override-ckeditor)
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/YzOrBmR>" %}
{% endtab %}

{% tab title="Guidance" %}
-Use the Text Area when larger text input is required

-Switch the Text Area to a WYSWIG to give the user the ability to format and customize the text input.
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Text Area",
  "autoExpand": false,
  "tableView": true,
  "key": "textArea",
  "type": "textarea",
  "input": true
}
```

#### Specific Properties

| Property | Description                                                  | Value                                                                               | Required | Default |
| -------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------- | -------- | ------- |
| rows     | How many rows this text area should contain.                 | Any `integer`                                                                       | `true`   | 3       |
| wysiwyg  | Determines if this text area should attach a wysiwyg editor. | `true` for default wysiwyg configuration, or a JSON object of the wysiwyg settings. | `false`  | false   |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Number

Use a Number field whenever a field should be limited to a number value type. You can configure options for thousands separators, decimal places, and decimal requirements.

{% tabs %}
{% tab title="Unique Settings" %}
**Use Thousands Separator:** Check this setting if you would like the value in this component to separate thousands by a local delimiter.

**Decimal Places:** The maximum number of decimal places for the values in this field.

**Require Decimals:** Always show decimals for this field, even if trailing zeros.

[**Decimal Symbol**: Change the default Decimal Symbol for the Number component.](#user-content-fn-13)[^13]
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/qByJoBq>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the Number component when dealing with input types that will be specific to numeric input
* Use the decimal places settings for numeric requirements like a percentage that may need specific decimal places included in the submission
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Number",
  "mask": false,
  "tableView": false,
  "delimiter": false,
  "requireDecimal": false,
  "inputFormat": "plain",
  "truncateMultipleSpaces": false,
  "key": "number1",
  "type": "number",
  "input": true
}
```

#### Specific Properties

<br>

<table><thead><tr><th>Property</th><th width="196">Description</th><th>Value</th><th width="116">Required</th><th>Default</th></tr></thead><tbody><tr><td>validate.min</td><td>The minimum value this number could be</td><td>Any number</td><td><code>false</code></td><td></td></tr><tr><td>validate.max</td><td>The maximum value this number could be</td><td>Any number</td><td><code>false</code></td><td></td></tr><tr><td>validate.step</td><td>The granularity of this number input</td><td>Any number</td><td><code>false</code></td><td><code>any</code></td></tr><tr><td>validate.integer</td><td>If this number should be an integer</td><td>boolean</td><td><code>false</code></td><td></td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Password

The password field has the same options as a text field component. It differs from a text field in that its HTML `<input>` type will be password instead of text. This will cause the field to display hidden input symbols instead of the entered value.

{% tabs %}
{% tab title="Unique Settings" %}
There are no unique settings for the Password component.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/rNrqdMx>" %}
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Password",
  "tableView": false,
  "key": "password1",
  "type": "password",
  "input": true,
  "protected": true
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Check Box

A check box can be used for boolean value input field. It can either be checked (true) or unchecked (false). There are options to set Shortcut and Input Type.

{% tabs %}
{% tab title="Unique Settings" %}
**Shortcut:** Add a keyboard shortcut to check/uncheck the component.

**Input Type:** The input type can be changed from a single input value checkbox or a multi-valued radio component.

The Radio type option is used when [**setting up dynamic Radio values**](/form-building/pdf-forms#checkboxes-and-radios) for a PDF First form.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/WNKazLN>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use [**Custom CSS Classes**](/form-building/pdf-forms#radio-and-checkbox-styles) to change the UI of the Checkbox.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Checkbox",
  "tableView": false,
  "key": "checkbox",
  "type": "checkbox",
  "input": true
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Select Box

This multi-valued component allows users to select one or more options in checkbox style format. Set your values within the Data tab of the settings. Apply unique settings such as value shortcuts and min/max value validation.

{% tabs %}
{% tab title="Unique Settings" %}
**Data Source Type:** The source to use for the Select Box options:

**Values:** Create your own list of static values for the Select Box options. The Label is the front-end identifier for the end user. The value is the back-end identifier for the option and is what is saved to the Database.

{% hint style="warning" %}
When setting the option ***value**,* use only Strings or Numeric values.
{% endhint %}

#### **Data Source URL:**

Designate a URL that will provide the option values for the Select Dropdown. Use the Item Template to determine what part of the URL's object will be used as.

{% hint style="info" %}
When the Data Source URL provides an **array** of JSON objects, you must specify a **Value** **Property** that corresponds to the desired property within each object which is set in the Item Template.

\
When the Data Source URL is a **string**, the **Value Property** setting can be left **empty**.
{% endhint %}

For instance, if you want to populate a Select Box with a list of U.S. states, you can achieve this by using an external JSON URL to supply the component's values.

1. Edit the Select Box settings and click the **Data** tab
2. Input the **Data Source URL** endpoint\
   \&#xNAN;*For example, copy and paste the location of* [*states.json*](https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FwmAq91bwK86ah0TVWHFb%2Fstates.json?alt=media\&token=bcf83383-f5e4-48b4-b977-4a0ad22b044e)
3. Configure the **Value Property** to match a specific property of the JSON object. This Value Property will be stored in the metadata to represent the option in the back end.

   ```
   abbreviation
   ```

{% hint style="info" %}
In this example, the **Data Source URL** endpoint is an **array,** so a proprety Value Property
{% endhint %}

4. Set the **Item Template** to configure the displayed value.\
   `{{ item.name }}`

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

This example is utilizing the follow URL endpoint containing the following JSON object structure:

```
[
    {
        "name": "Alabama",
        "abbreviation": "AL"
    },
    {
        "name": "Alaska",
        "abbreviation": "AK"
```

**Shortcut:** Add a keyboard shortcut for the designated option.

**Options Label Position:** Determines the position of the option label relative to it's checkbox

**Inline Layout:** Displays the option values horizontally

**Min/Max Checked Number:** Validation that determines the minimum and maximum amount of options to check. Checked options below the minimum will trigger front-end validation. When the maximum amount of options is checked, the remaining options will become disabled.

**Min/Max Checked Error Message:** Determines the validation message displayed to the user for the minimum or maximum option amount.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/MWBzmmB>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the **hamburger** icon to rearrange your options.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Select Boxes",
  "optionsLabelPosition": "right",
  "tableView": false,
  "defaultValue": {
    "a": false,
    "b": false,
    "c": false
  },
  "values": [
    {
      "label": "A",
      "value": "a",
      "shortcut": ""
    },
    {
      "label": "B",
      "value": "b",
      "shortcut": ""
    },
    {
      "label": "C",
      "value": "c",
      "shortcut": ""
    }
  ],
  "key": "selectBoxes",
  "type": "selectboxes",
  "input": true,
  "inputType": "checkbox"
}

```

#### Specific Properties

| Property      | Description                                                                                  | Value                     | Required | Default |
| ------------- | -------------------------------------------------------------------------------------------- | ------------------------- | -------- | ------- |
| hideLabel     | Whether to hide the checkbox label or not when showing it in the form.                       | `true` or `false`         | `false`  | `true`  |
| datagridLabel | The label to show as the column name when this element is placed within a data grid element. | Any `string`              | `false`  |         |
| name          | The HTML name to provide to this checkbox input                                              | Any valid HTML name value | `false`  |         |
| value         | The HTML value to provide to this checkbox input                                             | Any valid HTML value      | `false`  |         |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Select

The Select component displays a list of values in a dropdown list where users can select one of the values. This component has flexibility on where the data source originates from. There is also a large offering of settings providing different ways of filtering, querying, and loading data values.

{% tabs %}
{% tab title="Unique Settings" %}
**Widget Type:** Change the Select dropdown widget type:

[**Choices.js**](https://choices-js.github.io/Choices/)

[**HTML 5**](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select)

**Unique Options:** Display only unique dropdown options removing repeated values.

**Multiple Values:** Allows the user to select more than one option. Options are saved like tags on the field when the setting is enabled.

**Data Source Type:** The source to use for the Select component options:

**Value**, **URL**, **Resource**, **Raw** **JSON**, and **Custom.**

*(More information in the next tab Data Souce Types)*

**Storage Type:** Select how you want the field data to be stored. Defaults to 'Autotype' if an option is not selected:

String, Number, Boolean, Object

**ID Path:** Designate the path to select the option ID

**Item Template:** HTML template that determines how the Select options are displayed within the dropdown. You can use the **item** variable to access the current object in the array.

EG embed the value by using `{{ item.value }}` in a template.

**Lazy Load Data:** When set, a request will not be fired to the URL until this control is within focus. This can improve performance if you have many Select dropdowns on your form where the APIs will only fire when the field is activated.

**Request Headers**: Set any headers that should be sent along with the request to the url, useful for authentication.

**Data Path:** The property within the source data, where iterable items reside.

For example: results.items or results\[0].items

**Value Property:** The property of each item in the data source to use as the select value. If not specified, the item itself will be used.

**Disable Limiting Response:** When enabled, the request will not include the limit and skip options within the query string. This can help with unnecessary requests and performance.

**Search Query Name:** The name of the search query string parameter used when sending a request to filter results with. The server at the URL must handle this query parameter. If URL or Resource is selected as Data Source Type, enter the name of the search query parameter to filter requests with.

For example, if your URL is `http://api.dogs.com/dogs`, and Search Query Name is set to `type`, and then the user types `nice` in the Select field, then this component will send a request to `http://api.dogs.com/dogs?type=nice` and update the Select items with the results. If this option is omitted, no new requests will be made when a user enters text in the select field.

**Search Delay Request:** The delay in seconds before the search request is sent, measured from the last character input in the search field. The default is set to 0.3

**Filter Query:** Provide additional filtering within the dropdown using query parameters.

**Sort Query:** Provide additional sorting within the dropdown using query parameters.

|                     |                                                                                   |
| ------------------- | --------------------------------------------------------------------------------- |
| created             | Returns results based on created date of submissions values in ascending order    |
| -created            | Returns results based on created date of submissions values in desecending order  |
| data.propertyname   | Returns results based on alpha order of the submission values in ascending order  |
| -data.propertyname  | Returns results based on alpha order of the submission values in descending order |
| skip=10sort=created | skips the first 10 results based on creation date in ascending order              |
| skip=5sort=-created | skips the first 10 results based on creation date in ascending order              |

**Limit:** Use this to limit the number of items to request or view within the select field dropdown.

|    |                                                                                                                                    |
| -- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 10 | Returns only 10 values. When user scrolls to the bottom of the dropdown list, an API call is made returning the remaining results. |

**Formio Authenticate**: Check this if you would like to use Formio Authentication with the request.

**Disables Storing Request Result in the Cache:** Check it if you don't want the requests and their results to be stored in the cache. By default, it is stored and if the Select tries to request the same URL with the same parameters, the cached data will be returned. It allows to increase performance, but if the remote source's data is changing quite often and you always need to keep it up-to-date, uncheck this option.

**Refresh Options On:** Refresh the field options based on a change from another field on the form, or any change on the form. This is helpful when dealing with dynamic values, such as the [**Cascading Select Dropdowns**](https://github.com/formio/gitbook-docs/blob/main/tutorials/dynamic-select-filtering/README.md)

**Refresh Options On Blur:** Refresh the field options when a specific field or any field on the form is blurred[^14].

**Clear Value Option On Refresh:** Clears any selected value if the field is reset by the Refresh Options On setting.

**Enable Static Search:** When checked, the select dropdown will allow for searching within the static list of items provided.

**Search Threshold:** Determines when the select component match algorithm gives up. A threshold of 0.0 requires a perfect match, a threshold of 1.0 would match anything. This setting is set to 0.3 by default.

**Read Only Value:** Check this if you would like to only display the value when in Read Only mode.

**Choices.js options:** A raw JSON object to use as options for the Select component. Refer to the [**Choices.js documentation**](https://github.com/Choices-js/Choices#readme) for more information.

**Use Exact Search:** Disables the Search Algorithm and only allows exact searches to return an option.
{% endtab %}

{% tab title="Data Source Types" %}

### **Values**

Create your own list of static values for the select dropdown. The default source type for the Select component. The Label is the front-end identifier for the end user. The value is the back-end identifier for the option and is what is saved to the Database.

{% hint style="warning" %}
When setting the option ***value**,* use only Strings or Numeric values.
{% endhint %}

### **URL**

Designate a URL that will provide the option values for the Select Dropdown. Use the Item Template to determine what part of the URL's object will be used as the option values.

For example, suppose you wish to populate your Select dropdown with a list of all States of the U.S. You can use an external JSON URL like the following.

```
https://cdn.rawgit.com/mshafrir/2646763/raw/states_titlecase.json
```

Place the URL within the **Data Source URL**. Provide a **Value Property** to represent the option which is what will save within the meta-data. When the value is left blank, the entire object will be saved for the option. Modify the **Item Template** to determine what part of the object the end user will see when choosing an option.

In the image below, the abbreviation, which is set by the **Value Property**, will be saved in the meta-data to represent the option within the back end. The end user will see the State name, set by the **Item Template**, for the option on the front end.

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

**Data Source URL:** The URL that will return the JSON array

### **Resource**

Source of data is mapped to a Resource within your project to populate the entire Resource Object or underlying field data within the selected Resource as the Select component options.

**Resource:** Select which Resource within your project the Select component will map to. For additional information and design consideration, refer to the document "[Resource as Select Component Data Source](/form-building/basic-components/resource-as-select-component-data-source)."

**Value Property:** Select which field within the chosen Resource the Select component will pull data from. Leave this empty to reference the entire Resource object.

\*When a value property is selected, the Item Template will automatically be set based on your selection.

**Select Fields:** The properties on the resource to return as part of the options. Separate property names by commas. If left blank, all properties will be returned.

**Add Resource:** Dynamically adds a new record to the connected Resource

### **Raw JSON:**

Provide raw JSON data as the select field value.

**Data Source Raw JSON:** This is where you will save your JSON data

```
[{"name": "John", "email": "john.doe@test.com"}, {"name": "Jane", "email": "jane.doe@test.com"}].
```

###

### **Custom:**

Write custom code to provide value options for the Select component.

**Custom Values:** Write custom code to return the value options or a promise with value options. The form data object is available.

```
values = data['myKey'];
```

{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/KKBrBWY>" %}
{% endtab %}

{% tab title="Guidance" %}
**Organize your values**

Use the hamburger icon to rearrange your option values within the Select settings.

**Dynamic Select Filtering**

A very common use case that many people have in forms is to dynamically filter a Select dropdown based on the selection of another Select dropdown. The most typical use case is a form that provides the Make, Model and Year of vehicles where when you select the Make dropdown, it filters the Model dropdown for those that are inside that Make. This functionality is covered in detail in our [**user guide resources section**](https://help.form.io/form-building/resources/overview#dynamic-select-filtering).
{% endtab %}

{% tab title="JSON" %}

```json
{
  "label": "Select",
  "widget": "choicesjs",
  "tableView": true,
  "data": {
    "values": [
      {
        "label": "A",
        "value": "a"
      },
      {
        "label": "B",
        "value": "b"
      },
      {
        "label": "C",
        "value": "c"
      }
    ]
  },
  "key": "select1",
  "type": "select",
  "input": true
}
```

The Select component has many unique properties. [**Follow the link**](https://github.com/formio/formio.js/wiki/Select-Component) for more details
{% endtab %}
{% endtabs %}

### Radio

The radio component is a field that allows users to select a single option from a list of options displayed in radio-style format. Users can click a selected option to deselect it, returning the field back to its original state. allows

{% tabs %}
{% tab title="Unique Settings" %}
**Data Source Type:** The source to use for the Select Box options:

**Values:** Create your own list of static values for the Select Box options. The Label is the front-end identifier for the end user. The value is the back-end identifier for the option and is what is saved to the Database.

{% hint style="warning" %}
When setting the option ***value**,* use only Strings or Numeric values.
{% endhint %}

**Data Source URL:** Designate a URL that will provide the option values for the Select Dropdown. Use the Item Template to determine what part of the URL's object will be used as the option values.

*For example*, suppose you wish to populate your Select Box with a list of all U.S. States of You can use an external JSON by copying and paste the location of [*states.json*](https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FwmAq91bwK86ah0TVWHFb%2Fstates.json?alt=media\&token=bcf83383-f5e4-48b4-b977-4a0ad22b044e)

```
https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FwmAq91bwK86ah0TVWHFb%2Fstates.json?alt=media&token=bcf83383-f5e4-48b4-b977-4a0ad22b044e
```

Place the URL within the **Data Source URL**. Provide a **Value Property** to represent the option which is what will save within the meta-data. When the value is left blank, the entire object will be saved for the option. Modify the **Item Template** to determine what part of the object the end user will see when choosing an option.

In the image below, the abbreviation, set by the **Value Property**, will be saved in the meta-data to represent the option within the back end. The end user will see the State name, set by the **Item Template**, for the option on the front end.

<figure><img src="/files/pElR7hyponhHekFKj66H" alt="" width="495"><figcaption></figcaption></figure>

**Shortcut:** Add a keyboard shortcut for the designated option.

**Options Label Position:** Determines the position of the option label relative to the option bubble

**Inline Layout:** Displays the option values horizontally
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/QWBJVpj>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the hamburger icon to rearrange your option values.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Radio",
  "optionsLabelPosition": "right",
  "customClass": "pl-3",
  "inline": false,
  "tableView": false,
  "values": [
    {
      "label": "A",
      "value": "a",
      "shortcut": ""
    },
    {
      "label": "B",
      "value": "b",
      "shortcut": ""
    },
    {
      "label": "C",
      "value": "c",
      "shortcut": ""
    }
  ],
  "key": "radio",
  "type": "radio",
  "input": true
}
```

#### Specific Properties

| Property | Description               | Value                                                                                                                                                                                                                               | Required | Default |
| -------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
| values   | An array of value objects | <p>Array of value objects, where each item in the array has the following properties.</p><ul><li><strong>label</strong> - The label to show for this value</li><li><strong>value</strong> - The value of this radio input</li></ul> | `true`   | \[]     |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Button

Buttons can be added to perform various actions within the form. The most obvious function of the Button component is the Submission action. However, you can also utilize the Button component to trigger events associated with workflow logic, reset field data, authenticate to an OAuth provider, and more.

In addition to functionality, the button component offers many settings to change the style and theme of the component.

{% tabs %}
{% tab title="Unique Settings" %}
**Action:** The functionality that executes when the button is clicked. Click the event to show additional settings related to the selected action:

*Submit* - Submits the form to the back-end server

[*Save In State*](#user-content-fn-15)[^15] - This button action works alongside the Save In State workflow and facilitates a 'Save as Draft' workflow.

Inheritently the action will bypass validation giving the submission a different state.

*Reset -* Reset all fields on the form back to their pristine state

[*Event*](#user-content-fn-16)[^16] - Triggers an 'event' on the form which is usually correlated to application logic or form workflow logic

[*Oauth*](#user-content-fn-17)[^17] - Opens an OAuth authentication popup. This will only work after it has been assigned to an [**OAuth Action**](/form-building/actions/oauth-actions)**.**

See the [**OAuth guide**](/dev/authentication-and-authorization/oauth) for more information on how to set up OAuth in your project.

*Post to URL* -

[*Custom*](#user-content-fn-18)[^18] *-* Write custom code to fire

**Save On Enter:** Use the Enter key to submit the form

**Theme:** Set a theme (color) for the button mapped to [**Bootstrap**](https://getbootstrap.com/docs/4.6/components/buttons/) classes

**Size:** Determines the position of the option label relative to the option bubble

**Block Button:** Spans the button horizontally across the form

**Left/Right Icon:** Set an icon to the left or right side of the button label using [**Font Awesome**](https://fontawesome.com/search) icon classes.

**Disable on Form Invalid:** If any field on the form is invalid, disable the button.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/MWBzPJG>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the button component to Reset the fields on a form, clearing any data
* Fire off events using the button to initiate complex workflows in conjunction with other components like the [**Data Source**](/form-building/premium-components#data-source)
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Submit",
  "block": true,
  "leftIcon": "fa fa-send",
  "disableOnInvalid": true,
  "tableView": false,
  "key": "submit",
  "type": "button",
  "input": true,
  "saveOnEnter": false
}
```

The button component has many unique properties. [**Follow the link**](https://github.com/formio/formio.js/wiki/Button-Component) for more details.

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

[^1]: The type of widget

[^2]: Allows the user to manually input the Date/Time values. When set to 'false', the component will disable, forcing the end user to utilize the Calendar UI to select the date and time.

[^3]: When any part of the field is clicked, the Calendar picker will open and display for the end user. When set to 'false', the Calendar widget will only display when the calendar icon is clicked located at the suffix of the field.

[^4]: Enables the user to select or enter a date. When disabled, the widget displays only a time picker, date input won't be available to pick or input.

[^5]: Enables the user to select or enter a time. When disabled, the widget displays only a calendar picker, time input won't be available to pick or input.

[^6]: Removes the calenar picker from the field

[^7]: The date/time format that will display for the end user.

[^8]: The format that it saved in the database. This setting can be different than the 'format' setting'

[^9]: The amount the hour will increase or decrease when using the time picker UI.

[^10]: The amount the minute value will increase or decrease when using the time picker UI.

[^11]: Sets the time format to 24 hours

[^12]: Sets the minimum date that can be entered or selected from the calendar widget

[^13]: This is a hidden setting that can be configured by editing the Number component JSON. Add the following to the schema:

    ```
    "decimalSymbol": ","
    ```

    After saving your changes, the Number component will change the default decimal to the designated symbol. Use this in conjunction with the local delimiter to achieve different kinds of numbering systems.

[^14]: The onblur attribute fires the moment that the element loses focus (when a user leaves the field)

[^15]: **Show Validation** - Show any current Validations on the form

[^16]: **Button Event:** Name the event this button will output to the form.

[^17]: **Oauth Provider** - The OAuth provider to use to log in. Provider integration settings must be implemented within the Stage Settings

[^18]: **Custom Button Logic**: The custom logic to evaluate when the button is clicked.


# Resource as Select Component Data Source

Additional information and design considerations when using a Resource as the Data Source for a Select Component.

Using a Resource as the Data Source for the selectable choices in a Select Component is a common workflow. This permits, for example, user-defined data to be incorporated into the Select Component's choices. As the Resource is polled when the Form is rendered, the choices available in the Select Component can vary significantly between uses, which can significantly alter the data included in a Form submission.

When choosing to use a Resource as the Data Source for a Select Component, it is important to consider how Resource data is managed and what impact this has on Submission data. One important consideration to this end is the **"Save as reference"** option available in the Select Component settings.

<figure><img src="/files/P5yKOaGciesDP6q02RTo" alt="" width="563"><figcaption><p>Choices availalable when Data Source is set to Resource.</p></figcaption></figure>

To examine the impact of this option, consider the following Transport Request Form with a Driver Select Component that is populated from a Driver Resource.

<figure><img src="/files/NOL1SwYk6IrNybqU491r" alt=""><figcaption><p>The Select Component data source is a Resource.</p></figcaption></figure>

<figure><img src="/files/7oF0GAE7VAtOirv3xWUi" alt=""><figcaption><p>The Driver resource used to populate the Select Component</p></figcaption></figure>

The value chosen within the Select Component is stored in the Submission Data as expected:

<figure><img src="/files/gMYNySfsdtS3Q18rzqqk" alt=""><figcaption><p>Submission Data with the Driver recorded.</p></figcaption></figure>

As with the [Nested Form component](/form-building/nested-forms), enabling the "Save as reference" function affects the way edited Submissions are recorded. When "Save as reference" is enabled, editing the resource following a submission will update the data in the recorded submission:

<figure><img src="/files/WRRB9mJKOyuBqLajjLrT" alt="" width="563"><figcaption><p>Editing a submission of the Driver Resource.</p></figcaption></figure>

<figure><img src="/files/CexDdrodm7tnpS9hbzrg" alt="" width="563"><figcaption><p>The Resource Data tab, reflecting the update.</p></figcaption></figure>

After editing the resource, any submissions recorded while the Select component was configured to "Save as reference" will reflect the update:

<figure><img src="/files/mFqEbKXSP9kALxWMaprd" alt=""><figcaption><p>The updated field is reflected in the Form Submission Data.</p></figcaption></figure>

{% hint style="info" %}
Note that even though the data recorded was updated, and the Resource's "Updated" field reflects the time, the original submission's "Updated" time does **not** change.
{% endhint %}

In contrast, the Submission of the form where "Save as reference" is **not** configured will retain the same data:

<figure><img src="/files/gMYNySfsdtS3Q18rzqqk" alt=""><figcaption><p>Data remains unchanged when "Save as reference" is <strong>not</strong> configured.</p></figcaption></figure>

### Data Stability and Race Conditions

It is important to consider that when using a Resource as the Data Source for a Select Component, multiple actors within the project may be editing the Resource at any time.\
If the Resource is configured with "Save as reference," it is possible for Submission data to change if the resource is edited any time after the Submission is recorded. When this effect is intended, it is important to factor this into the application as a whole, as cached versions of the Submission data may not reflect such updates. Be careful to account for all downstream considerations that may arise when Submission data is configured to change synchronously with the Resource field.

Additionally, it is important to remember that a Form may directly or indirectly affect a Resource used as a Data Source within itself. This can create unanticipated and unpredictable behavior. Ensure that all workflows within the application that may alter a Resource that is used as a Data Source are sufficiently decoupled from processes that rely on that Resource as an input.

The following diagrams illustrate the relationship between the Select Component, the Resource, and the Submission, and the way the "Save as reference" option affects this relationship.

In the first example, the Resource supplies selectable fields for the Select Component's drop down. When one of these is selected and the form is submitted, the Submission will record the selected value as it was stored in the Resource at the time of the submission.

<figure><img src="/files/GbMSilc8k09PS0THnLzc" alt=""><figcaption><p>The Resource serves as the Data Source for the Select Component. The selected field is submitted.</p></figcaption></figure>

In the next illustration, the Resource is modified, but "Save as reference" is not selected. As a result, only submissions made after the change will reflect the alteration.

<figure><img src="/files/NqRMEDMZRIDYt9X3BPd1" alt=""><figcaption><p>Without "Save as reference" configured, only new Submissions will store an edited value.</p></figcaption></figure>

In the final illustration, "Save as reference" is selected. As a result, the previously recorded submission will reflect the change to the Resource, even if no new submission is made.

<figure><img src="/files/rrBkH4grpoAtklgBJTcW" alt=""><figcaption><p>The previously recorded Submission may be changed when "Save as Reference" is enabled.</p></figcaption></figure>


# Advance Components

Using and configuring Advanced Components in the Form Builder

Advanced Components are often Basic Components that have been extended to meet more complex requirements. You can find information for each of the Advanced Components like unique settings, JSON code, and field examples below:

{% embed url="<https://youtu.be/izpHZ4mwHEQ>" %}

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Email</strong></td><td>Input field with validation ensuring email format.</td><td></td><td><a href="#email">#email</a></td></tr><tr><td><strong>URL</strong></td><td>Input field with validation ensuring a URL format.</td><td></td><td><a href="#url">#url</a></td></tr><tr><td><strong>Phone Number</strong></td><td>Input field with a mask that allows numeric format.</td><td></td><td><a href="#phone-number">#phone-number</a></td></tr><tr><td><strong>Tags</strong></td><td>Categorize items on your form or use for tags for logic.</td><td></td><td><a href="#tags">#tags</a></td></tr><tr><td><strong>Address</strong></td><td>Input field with Location provider support for address lookup and map.</td><td></td><td><a href="#address">#address</a></td></tr><tr><td><strong>Date &#x26; Time</strong></td><td>Input or select a date and time for a calendar picker widget.</td><td></td><td><a href="#date-and-time">#date-and-time</a></td></tr><tr><td><strong>Day</strong></td><td>A three field component that represents Day/Month/Year.</td><td></td><td><a href="#day">#day</a></td></tr><tr><td><strong>Time</strong></td><td>Input to add a time or select a time from a predefined widget.</td><td></td><td><a href="#time-1">#time-1</a></td></tr><tr><td><strong>Currency</strong></td><td>Input field that supports many different currency types.</td><td></td><td><a href="#currency">#currency</a></td></tr><tr><td><strong>Survey</strong></td><td>Questions and correlated answers in survey format.</td><td></td><td><a href="#survey">#survey</a></td></tr><tr><td><strong>Signature</strong></td><td>Digitally sign on a signature pad.</td><td></td><td><a href="#signature">#signature</a></td></tr></tbody></table>

### Email

The Email component is a string field that carries special input validation ensuring the entered data is in a valid email format. A valid email address consists of an email prefix and an email domain, both in acceptable formats.

{% tabs %}
{% tab title="Unique Settings" %}
**Realtime Kickbox.io Validation:** In addition to the normal email format validation, bring real-time Email validation through our integration with [**Kickbox.io**](https://kickbox.com/).
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/wvxRWQQ>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the Validate On 'Blur' setting to ensure validation formatting is only triggered when the user has left the field.
* When using an Email action on your form, interpolate the email data and send off the email action to the email address entered in the field

```
{{ data.email }}
```

{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Email",
  "tableView": true,
  "key": "email",
  "type": "email",
  "input": true
}
```

#### Specific Properties

| Property        | Description                                                      | Value   | Required | Default |
| --------------- | ---------------------------------------------------------------- | ------- | -------- | ------- |
| kickbox.enabled | If the Kickbox validation should be enabled for this email input | boolean | `false`  | `false` |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### URL

Similar to the Email field, the URL component is a string field that carries special input validation ensuring the entered data is in a valid URL format. Validation will check to see if the entered input data is at least in the correct format to potentially be a legitimate URL.

{% tabs %}
{% tab title="Unique Settings" %}
There are no unique settings for the URL component.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/abjPwVd>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the [**Validate On 'Blur'**](/form-building/component-settings#validate-on) setting to ensure validation formatting is only triggered when the user has left the field.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Url",
  "tableView": true,
  "key": "url",
  "type": "url",
  "input": true
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Phone Number

The Phone Number field carries an input mask to force the user to enter the field data in Phone Number format.

EG (123) 123-1234

{% tabs %}
{% tab title="Unique Settings" %}
There are no unique settings for the Phone Number component.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/bGjORmQ>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the [**Validate On 'Blur'**](/form-building/component-settings#validate-on) setting to ensure validation formatting is only triggered when the user has left the field.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Phone Number",
  "tableView": true,
  "key": "phoneNumber",
  "type": "phoneNumber",
  "input": true
}
```

#### Specific Properties

| Property  | Description                                 | Value              | Required | Default        |
| --------- | ------------------------------------------- | ------------------ | -------- | -------------- |
| inputMask | The input mask for this phone number input. | A valid input mask | `true`   | (999) 999-9999 |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Tags

The Tag component draws attention to or categorizes elements on your form. Multiple tags can be added to one Tag field.

{% tabs %}
{% tab title="Unique Settings" %}
**Delimiter:** The character used to separate tags

**Max Tags:** The maximum amount of tags that can be added.

**Store As**: Determines how the tag data will be stored once submitted.

String (CSV)

Array of Tags
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/WNKLEvq>" %}
{% endtab %}

{% tab title="Guidance" %}

* **To draw attention to new, important content.** Tags can focus attention on important content that might otherwise be missed.
* **Business Logic.** Use tags to facilitate form-level or application-level logic and conditional workflows.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Tags",
  "tableView": false,
  "key": "tags",
  "type": "tags",
  "input": true
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Address

The Address component is a special component that performs an address lookup based on user input using several map and location providers as well as Custom Provider support. Address data can also be entered in free form and will save the address as well as geolocation and other metadata.

<details>

<summary>Google Map Integration Guide</summary>

<mark style="background-color:yellow;">Due to recent changes to the Google Maps API usage policies, an enabled Maps Javascript API and valid Maps API Key are required for all Address lookups using the Google Maps provider. Follow the instructions below to generate your Google Map API key.</mark>

1. Navigate to the [**Google Maps Platform** ](https://mapsplatform.google.com/)and click the **Get Started** button\
   \
   Follow the steps and Google will create a Project and Maps API key. Copy the **API key** and ensure you check the '**Enable all Google Maps API's for this project**' setting\
   \
   If you've never used the Google Cloud Platform before, follow the steps below to generate an API key.

<img src="/files/mycC6vKJ9E89OoPLwGmt" alt="" data-size="original">

2. Navigate to the Google Maps Platform and click the ' **Enabled API's and services**' tab to view enabled API's (ensure the Maps Javascript API is included in the 'API's and services' section)

![](/files/4RvQMFTmNbtSJmo4SVPP)

3. Click the Credential tab to review or copy your Map API key if you did not do so in the previous step

![](https://lh5.googleusercontent.com/HRL9RVLHs4m64c3trTTdn5RIPPEM2gYXsyALGEMzs_goYiCYfM8Jc4Ssd_3dTGCMXBTaFXmeYZwflF87UCvs99Za_vgtxyJ6Y7T3-9gtLF5lOXVsqCm3MDVQpMjYrH-D7v82twvN5roovASNm6M_mNk)

It's advised to restrict your API key to prevent unauthorized usage. Edit your API key to add restriction parameters

![](https://lh3.googleusercontent.com/3iusk7k3E-F5fxEKqVqLUCceXyALbWSvksnDvxvhIkKK-cMZdoLSpaLILijYBwJ9KmJLBCcAAnrOSljBZN90zqUdPi9E-XQpv_pDBHkENB6msdKKoPq5_TOR6FpnLKnVbM-ojmfKDF2PjrXYTI-b7do)

4. Login to Form.io and add an **Address** component to a form
5. Inside the Address settings, click the **Provider** tab, select Google Maps, and paste your **Google Maps API key**

![](https://lh4.googleusercontent.com/NACOkorRMH9au3aZmHjizoEQE3sPNjCVnfusz2adw9hZYc5y9eZP3Fw9Ex8RnCR53r8rzRG5iofZzFjxHtO7kEVzbCGA9ggGSz0ptY65tDCXk0E2srJ7A19ldPbmcwGEL4dY6R3j-kEYllqHbCEYya4)

6. Use the form and the Address component will perform a lookup and populate results as the user inputs data into the field

![](https://lh6.googleusercontent.com/PPQDvat3xgzKy6fhLEZqtqH-1i_hvTYrxsgIu96EeR9Hy5CPwwyJZCSzHifFzvIFpPTyHhaj4tgZKdJwlLoS3h1GWd84NlMonv91pbsLMZ9-SY6TObtge_17CHQZ9EluTjC4ACilOv991OFyrsikFqg)

<br>

</details>

{% tabs %}
{% tab title="Unique Settings, Address" %}
**Enable Manual Mode:** Checking this setting adds a checkbox under the Address field. Should the user check this, the address lookup through the location provider is disabled, and the traditional address field will display for manual input (Address, City, State, Zip etc)

**Switch To Manual Mode Label:** The label of the checkbox used for the 'Enable Manual Mode' setting.

**Disable Clear Icon:** Removes the 'x' clear icon found at the far right of the field. You may want to check this setting to prevent any users from accidentally clicking the icon.

### **Providers**

Form.io is integrated with several Location and Map providers for fast and easy address lookup and geolocation data.

**Azure Maps:** Set up your own [**Azure Map**](https://learn.microsoft.com/en-us/azure/azure-maps/) account and provide the subscription key to enable this map provider.

**Open Street Map Nominatim:** [**Nominatim**](https://nominatim.org/release-docs/latest/) is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points

**Custom:** Provides settings to integrate your own custom map provider.

**Google Maps:** Set up a Google Map API to utilize Google's location and map technology. Please see the documentation above for a full guide on integration setup with Form.io

**Manual Mode View String:** Specify the template to be used when querying the view string for component values entered in manual mode. This string is used in the table view, CSV export, and email rendering. When left blank combined value of all components joined with a comma will be used.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/QWBRxxW>" %}
{% endtab %}

{% tab title="Guidance" %}
Coming Soon...
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Address",
  "tableView": false,
  "provider": "nominatim",
  "key": "address1",
  "type": "address",
  "providerOptions": {
    "params": {
      "autocompleteOptions": {}
    }
  },
  "input": true,
  "components": [
    {
      "label": "Address 1",
      "tableView": false,
      "key": "address1",
      "type": "textfield",
      "input": true,
      "customConditional": "show = _.get(instance, 'parent.manualMode', false);"
    },
    {
      "label": "Address 2",
      "tableView": false,
      "key": "address2",
      "type": "textfield",
      "input": true,
      "customConditional": "show = _.get(instance, 'parent.manualMode', false);"
    },
    {
      "label": "City",
      "tableView": false,
      "key": "city",
      "type": "textfield",
      "input": true,
      "customConditional": "show = _.get(instance, 'parent.manualMode', false);"
    },
    {
      "label": "State",
      "tableView": false,
      "key": "state",
      "type": "textfield",
      "input": true,
      "customConditional": "show = _.get(instance, 'parent.manualMode', false);"
    },
    {
      "label": "Country",
      "tableView": false,
      "key": "country",
      "type": "textfield",
      "input": true,
      "customConditional": "show = _.get(instance, 'parent.manualMode', false);"
    },
    {
      "label": "Zip Code",
      "tableView": false,
      "key": "zip",
      "type": "textfield",
      "input": true,
      "customConditional": "show = _.get(instance, 'parent.manualMode', false);"
    }
  ]
}
```

#### Specific Properties

| Property | Description                                                           | Value                                                                                                                                                                 | Required | Default |
| -------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
| map      | A description of the map settings for configuring the Google Maps API | <ul><li><strong>map.region</strong> - The region configuration for the map.</li><li><strong>map.key</strong> - The API key for the Google Maps integration.</li></ul> | false    | {}      |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Date & Time

The Date/Time component is a powerful and flexible option that supports advanced features such as validation, date range restrictions, and date calculations using [**Moment.js**](https://momentjs.com/docs/). It stores data as an ISO 8601 date, making it ideal for forms that require precise date/time handling, filtering, and validation. Due to its ISO-based format, it's also the preferred choice when timezone awareness is necessary.

<details>

<summary>What Type of Date/Time Field Should I Use?</summary>

Form.io provides two different Date and Time picker components: a string-based [**Textfield**](/form-building/basic-components#text-field) with an integrated Calendar Widget, and a dedicated Date/Time picker component. Choosing which component to use depends on the use case of your user base and application.

**Textfield Component with Calendar Widget:** A string-based [**Textfield**](/form-building/basic-components#text-field) component with an integrated Calendar Widget. This component stores dates as plain strings, meaning the saved values remain fixed and do **not** adjust based on the user's location or timezone. When viewing the submitted data, it will appear exactly as entered, regardless of where or when it's viewed.

*Example: Birthday Field*

If you're designing a form that includes a field for users to select their birthday, the Textfield Calendar Widget is an ideal choice. Since the date is a static string, the birthday remains unchanged no matter where the submission is viewed or what timezone the viewer is in.

**Date/Time Component**

This component stores data as an ISO 8601 date, making it ideal for forms that require precise date/time handling, filtering, and validation. Due to its ISO-based format, it's also the preferred choice when timezone awareness is necessary.

*Example: Live Stream Event Field*\
If you're designing an invitation form that includes a date field indicating the time of an event, the Date/Time component is an ideal choice. Since the component uses the ISO date format, the event date and time can automatically adjust to match the viewer’s local timezone, informing the user of the correct event time based on their location.

</details>

{% tabs %}
{% tab title="Unique Settings" %}
**Display In Timezone:** This setting will determine how the user will view the captured Date/Time based on the type of Timezone value selected. These settings can dynamically change based on the user's location and setting type.

<sup>***Of Viewer***</sup>\
Date/Time values will display in the viewer's local time zone, automatically adjusting according to the user's location. Use this setting when the value should display in the user's local time zone.

<sup>***Of Submission***</sup>\
Use this setting to maintain the submission’s original timezone. When the submission is viewed in a different timezone, an indicator will display within the field showing the original timezone.

<sup>***Of Location***</sup>\
When this value is set, a new dropdown field will appear within the Date/Time component settings where a specific timezone is selected. Date/Time data will display based on the timezone location specified within the settings. When a submission is viewed from a location other than the set location, an indicator showing the set time zone will appear next to the value. Use this setting when the value should display in a set timezone.

<sup>***UTC***</sup>\
Date/time values are displayed in UTC, ensuring a standardized reference point across all users and systems. This setting is ideal when uniformity is required, regardless of the viewer's local time zone. Use this setting when the value should consistently display in UTC.

**Use Local Settings**: Use the Date/Time of your local machine

**Allow Manual Input:** Set by default, this setting will allow you to use your keyboard to input the value. When unchecked, the user will only be able to select the Date and Time from the calendar widget.

**Format:** The format the Date/Time will display in. By default, the format will be set to:

```
yyyy-MM-dd hh:mm a
```

Use formats provided by [**DateParser Codes**](https://github.com/angular-ui/bootstrap/tree/master/src/dateparser/docs#uibdateparsers-format-codes) for more options

### Date

**Enable Date Input:** Enables select-able dates in the calendar widget and user input.

**Disable Specific Dates:** Blacklist certain dates by providing a date in the following format:

<pre><code><strong>(yyyy-MM-dd) or (yyyy-MM-dd - yyyy-MM-dd)
</strong></code></pre>

**Custom Disabled Dates:** Write JavaScript to customize your disabled dates

```
// Disable all weekends
date.getDay() === 0 || date.getDay() === 6
```

**Disable Weekends/Weekdays:** Disables the selected days from the calendar picker.

### Time

**Enable Time Input:** Enable or Disable the time input.

**Hour/Minute Increment:** Change the increment value when selecting a time from the Calendar Widget using the increment buttons.

**12 Hour Time (AM/PM):** Display time in 12-hour time with AM/PM.

### Data

**Flatpickr options:** add new/override current Flatpickr options.

This field can be used to set the options of the Flatpickr library, which is used to create the date-picker widget. A full list of the options can be found [**here**](https://flatpickr.js.org/options/).

It can also be used to set a translation for the date-picker. To do so, the user has to provide a value to the `locale` variable. In the following example, translation is set to French with the shorthand name of the locale:

```json
{ "locale": "fr" }
```

A full list of the available locales and their shorthand names can be found [**here**](https://github.com/flatpickr/flatpickr/tree/master/src/l10n).

### Validation

**Default Date:** Set a default Date and Time when a user renders the form. Utilize Moment.JS to set dynamic date ranges.

For example, this code will set the date to 10 days before the current date by default

```
moment().subtract(10, 'days')
```

**Use Calendar To Set Min/Max Date:** Click in the setting field to open a Calendar to pick the minimum or maximum date.

**Use Moment.js To Set Min/Max Date**: Check this if you would rather use Moment.js to set your dates rather than the calendar picker
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/OJwYdMw>" %}
{% endtab %}

{% tab title="Guidance" %}
Coming Soon...
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Date / Time",
  "customClass": "pl-3 pr-3",
  "tableView": false,
  "datePicker": {
    "disableWeekends": false,
    "disableWeekdays": false
  },
  "enableMinDateInput": false,
  "enableMaxDateInput": false,
  "key": "dateTime",
  "type": "datetime",
  "input": true,
  "widget": {
    "type": "calendar",
    "displayInTimezone": "viewer",
    "locale": "en",
    "useLocaleSettings": false,
    "allowInput": true,
    "mode": "single",
    "enableTime": true,
    "noCalendar": false,
    "format": "yyyy-MM-dd hh:mm a",
    "hourIncrement": 1,
    "minuteIncrement": 1,
    "time_24hr": false,
    "minDate": null,
    "disableWeekends": false,
    "disableWeekdays": false,
    "maxDate": null
  }
}
```

[**Click here for a list of the Date/Time properties specific to this component**](https://github.com/formio/formio.js/wiki/)

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Day

The Day component is used to enter values for the Day, Month, and Year using a number or select type of field.

{% tabs %}
{% tab title="Unique Settings" %}
**Hide Input Labels:** Hide the labels of component inputs. Labels will be visible when using the Form Builder but hidden when the form is rendered.

**Type of Input:** Determines the type of input the user will use for the field:

* Number - Number input that represents the field
* Select - Select values representing the date option

**Hidden:** When checked, this specific field (day/month/year) will be hidden from the set of Day components. When a field is hidden, that value will be absent from the value as stored in the submission. For example, enabling **Hidden** on the component and entering *January 2024* will be saved as `01/2024`.

**Day First:** When checked, the day field will display first from the set of Day components.

**Placeholder:** Text displayed inside the field and removed when there is user input.

{% hint style="info" %}
Following the release of Form.io Enterprise 9.3.0, the value recorded for any unfilled field is an empty string (''). Prior to this release, empty fields were interpreted as '0'.
{% endhint %}
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/MWBdLLe>" %}
{% endtab %}

{% tab title="Guidance" %}
Coming Soon...
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Day",
  "hideInputLabels": false,
  "inputsLabelPosition": "top",
  "useLocaleSettings": false,
  "tableView": false,
  "fields": {
    "day": {
      "hide": false
    },
    "month": {
      "hide": false
    },
    "year": {
      "hide": false
    }
  },
  "key": "day",
  "type": "day",
  "input": true,
  "defaultValue": "00/00/0000"
}
```

The Date/Time has many unique properties, [**follow the link**](https://github.com/formio/formio.js/wiki/) for more information.

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Time

A stand-alone time field for manual input or a time selector widget.

{% tabs %}
{% tab title="Unique Settings" %}
**Input Type:** The type of widget the Time field will use:

HTML5, Text input with mask

**Format**: Set the formatting for the time when the Text input with mask setting is set.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/BaPqwqr>" %}
{% endtab %}

{% tab title="Guidance" %}
Coming Soon...
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Time",
  "customClass": "pr-3 pl-3",
  "tableView": true,
  "key": "time",
  "type": "time",
  "input": true,
  "inputMask": "99:99"
}
```

| Property | Description                                       | Value                        | Required | Default |
| -------- | ------------------------------------------------- | ---------------------------- | -------- | ------- |
| format   | The time format for display of the captured time. | Any valid time format string | `true`   | `HH:mm` |

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Currency

Use the Currency component when a field needs to display monetary amounts. This component holds a numeric input mask that allows two decimal values and automatically adds commas as a user inputs a currency amount. The type of currency can also be selected which will change the prefix currency symbol.

{% tabs %}
{% tab title="Unique Settings" %}
**Currency:** The type of currency symbol and format the field will display when a user inputs into the field.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/JjBqzGv>" %}
{% endtab %}

{% tab title="Guidance" %}
Coming Soon...
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Currency",
  "mask": false,
  "spellcheck": true,
  "tableView": false,
  "currency": "USD",
  "inputFormat": "plain",
  "truncateMultipleSpaces": false,
  "key": "currency",
  "type": "currency",
  "input": true,
  "delimiter": true
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Survey

The Survey component works similarly to the [**Radio** ](/form-building/basic-components#radio)component. Instead of one question, users are able to select a value for multiple questions which are configured within the component settings. Survey is a great component to utilize when asking multiple questions with the same context of answers or values.

{% tabs %}
{% tab title="Unique Settings" %}
**Questions:** The questions presented to the user, displayed vertically in the left-hand column

**Values:** Values are the answer that can be selected for each question.

**Tooltip:** Add a tooltip to any of the Questions or Values to help better communicate with your users.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/GRBaerV>" %}
{% endtab %}

{% tab title="Guidance" %}
**Examples**

**Response Calculation:**

In some cases, you may want to set up logic on a Number field to calculate the average of the survey responses. To start, ensure the answers for your Survey component are represented by numeric values.

Add a Number field to your form and add the following logic:

```
value = Object.values(data.survey).reduce(function(sum, value) {  return sum + parseInt(value); }, 0);
```

{% hint style="info" %}
The data.**survey** within. code above is the Property Name of the Survey component
{% endhint %}

Navigate to [**https://formio.github.io/formio.js/app/sandbox**](https://formio.github.io/formio.js/app/sandbox) and use the following ID for a hands-on example:

631a5562621b15344c769e42
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Product Rating",
  "customClass": "pl-3 pr-3",
  "tableView": false,
  "questions": [
    {
      "label": "Ease of Use",
      "value": "easeOfUse",
      "tooltip": "Was our product easy to use without any problems?"
    },
    {
      "label": "Customer Support",
      "value": "customerSupport",
      "tooltip": "Was our customer support team timely and effective?"
    },
    {
      "label": "Onboarding Process",
      "value": "onboardingProcess",
      "tooltip": "Was our onboarding process easy to follow and execute?"
    }
  ],
  "values": [
    {
      "label": "Very Dissatisfied",
      "value": "1",
      "tooltip": ""
    },
    {
      "label": "Dissatisfied",
      "value": "2",
      "tooltip": ""
    },
    {
      "label": "No Opinion",
      "value": "3",
      "tooltip": ""
    },
    {
      "label": "Satisfied",
      "value": "4",
      "tooltip": ""
    },
    {
      "label": "Very Satisfied",
      "value": "5",
      "tooltip": ""
    }
  ],
  "key": "survey",
  "type": "survey",
  "input": true
}
```

#### Specific Properties

<table><thead><tr><th width="130">Property</th><th width="166">Description</th><th width="389">Value</th><th width="242">Required</th><th>Default</th></tr></thead><tbody><tr><td>questions</td><td>An array of question objects</td><td><p>An array of question objects, where each question object contains the following properties.</p><ul><li><strong>label</strong> - The label of the question.</li><li><strong>value</strong> - The value of this question used to store the value of this component.</li></ul></td><td><code>true</code></td><td>[]</td></tr><tr><td>values</td><td>An array of value objects</td><td><p>Array of value objects, where each item in the array has the following properties.</p><ul><li><strong>label</strong> - The label to show for this value</li><li><strong>value</strong> - The value of this radio input</li></ul></td><td><code>true</code></td><td>[]</td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Signature

The Signature component allows the end-user to digitally sign a signature pad with either their finger on a touch-enabled device or with the mouse pointer. When the form is submitted, the Signature pad will be converted into an image and stored with the form submission.

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

{% tabs %}
{% tab title="Unique Settings" %}
**Provider:** This drop-down will determine what kind of Signature pad to use.

**Default:** Standard digital signature that can be signed upon form submission
{% endtab %}
{% endtabs %}


# Premium Components

Using and configuring Premium Components in the Form Builder

## Instructions for Use of Form.io Premium Components

Form.io provides access to modules that contain premium components and themes for enterprise plans on license basis. In order to use them, you will need to obtain Library License key and apply it in your application.

1. Contact [**sales@form.io**](mailto:sales@form.io) in order to get the Library License key for premium components (if you don't yet have a license key with premium package enabled).
2. Install the package from [npm](https://www.npmjs.com/package/@formio/premium).

   ```
   npm install @formio/premium
   ```

   This will install the package within your application.
3. In your codebase, set the license key on Formio.license in the main file of your app. Then Formio.use() the package. Depending on your language, do something like the following. (With react or vue, import Formio from react-formio or vue-formio instead of formiojs).

   ```
   import { Formio } from '@formio/js';
   import premium from '@formio/premium';

   Formio.license = 'yourLibraryLicenseKey';
   Formio.use(premium);
   ```
4. Render forms as usual. Premium components will now be installed in your app.

{% hint style="info" %}
When configuring an application to include premium components, the Premium License must be referenced. This is a unique license that is separate from any other Platform, Developer, or Deployment licenses.
{% endhint %}

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Data Source</strong></td><td>Store external data to perform form or application logic</td><td></td><td><a href="#data-source">#data-source</a></td></tr><tr><td><strong>CAPTCHA</strong></td><td>Secure your forms with CAPTCHA technology V3</td><td></td><td><a href="#captcha">#captcha</a></td></tr><tr><td><strong>File</strong></td><td>Upload files from your mobile camera or local machine</td><td></td><td><a href="#file">#file</a></td></tr><tr><td><strong>Nested Form</strong></td><td>Reuse forms by inserting child forms into parent forms.</td><td></td><td><a href="#nested-form">#nested-form</a></td></tr><tr><td><strong>Tagpad</strong></td><td>Tag points on an image with associated fields</td><td></td><td><a href="#tagpad">#tagpad</a></td></tr><tr><td><strong>Sketchpad</strong></td><td>Draw or add predefined shapes on images</td><td></td><td><a href="#sketchpad">#sketchpad</a></td></tr><tr><td><p><strong>Review Page</strong></p><p>Summary of data input of fields on the form.</p></td><td></td><td></td><td><a href="#review-page">#review-page</a></td></tr><tr><td><strong>Custom</strong></td><td>Use field JSON schema to create custom fields.</td><td></td><td><a href="#custom">#custom</a></td></tr><tr><td><p><strong>Data Table</strong></p><p>Fetch data from external sources for user selection.</p></td><td></td><td></td><td><a href="#data-table">#data-table</a></td></tr></tbody></table>

## **Data Source**

**‌What is the Data Source?**

The Data Source component is a hidden form component that is typically used to fetch data from an external source using an API endpoint. This component will not be visible to the end user but the stored data can be used for various reasons and use cases such as custom validation, calculation, data outputs, and more.

**Using the Data Source Component**

To use the Data Source, start by dragging and dropping the field from the Premium component grouping in the Form Builder. Although the component is hidden when rendered, the field is visible while editing the form.

First, configure the **Fetch** URL, which is the source of data the component will access.\
The Data Source component does not do anything to the accessed data itself; it is strictly a mechanism to make external data available for fields and variables to use in certain functions like field or application logic.

The data accessed by the Data Source component is not stored in the submission and is lost when the form is closed or submitted. This means that conditions based on information retrieved by Data Source need to save the data in some other form. This is often handled by caching the value in a component and basing conditionals on that stored data.

{% hint style="info" %}
Prior to Formio-Enterprise 9.x, Data Source data was stored as part of the submission. This could result in extraordinarily large data sets being stored depending on the format of the accessed data.
{% endhint %}

Below shows an example of the Data Source being used to fetch Data from an external URL and using the Trigger to execute business logic on the form.

**Example Using External API URL**

This example fetches data from an external API URL hosting JSON containing a list of USA states. This data is then used in a checkbox on the form to trigger a Data Source event. That triggered event will then execute calculated logic to output the fetched data to fields inside a Data Grid.

Start off by adding the Data Source component to the builder. Within the settings, click the **Fetch** tab and add the following to the **URL** field:

```
https://gists.rawgit.com/mshafrir/2646763/raw/states_titlecase.json
```

<figure><img src="/files/LYy6Db9SQQrKjDg0PuNq" alt=""><figcaption><p>Data Source Fetch Settings</p></figcaption></figure>

Next, let's add our trigger component to the form. Add a Checkbox and name the component 'Populate'. Open the Data Source settings and click the **Trigger** tab. Click the **Trigger on data change** dropdown and select the 'Populate' checkbox from the form. This component will act as the Trigger to execute the event. Next, add the following for the **Triggered Event** which will be the event sent to the Form when the Trigger component is checked:

```
populateState
```

<figure><img src="/files/Zfi2olk4zo2UY8YYdQAp" alt=""><figcaption><p>Data Source Trigger Settings</p></figcaption></figure>

For our final step, we need to add the fields that will host the data population and configure Logic for those fields to execute when the Data Source event has been received.

First, let's add a Data Grid to the form. Because we are going to fetch data with many entries we need the Data Grid to ensure we have the necessary rows to populate the states. Add two text fields called Name and Abbreviation. Ensure the [**Property Name**](/form-building/component-settings#property-name) for the fields matches the JSON values from the Fetch step.

Now that we have our fields in place, we need to add logic to the Data Grid to populate the data from our Data Source to the fields inside the grid. Edit the Data Grid settings and click the **Logic** Tab. Set the **Trigger Type to Event** and add the Event Name: '**populateState**' to match our Data Source event. Set the **Action** **Type** to **Value** and add the following to the JavaScript content:

```
value = data.dataSource;
```

{% hint style="info" %}
Please note, the property name reference inside the Javascript should match the Data Source property name.
{% endhint %}

You should have a form looking something like this:

<figure><img src="/files/EP9jfjAbJKqRgR29otTb" alt=""><figcaption><p>Data Source Form Using The Form Builder</p></figcaption></figure>

The only thing left to do is test our form. When the Populate checkbox is ticked, the Data Source is triggered to fetch the Data and fire off an event. Our Data Grid contains logic that is listening for the event and will populate the Data being stored from the Data Source to our Name and Abbreviation fields inside the Data Grid. Because our Name and Abbreviation field's property name matches the names inside the JSON URL, the data population will calculate the fields seamlessly.

{% tabs %}
{% tab title="Unique Settings" %}

### **Trigger**

The Trigger Settings will determine how and when the external data will be stored in the Data Source component.

**Trigger on Form Init:** ‌Loads data once the form is rendered and ready for use.

**‌Trigger on Server:** Loads data on the server during validation.

**‌Trigger on Data Change:** Specifies a component the value change of which will have the data stored in the Data Source component be refreshed. A new request will be sent again.

**‌Trigger on Blur of Component:** **‌**Specifies a component on which blur, data stored in the Data Source component should be refreshed. A new request will be sent again.

**‌Trigger on Event: ‌**Specifies the name of the event on which data stored in the Data Source component should be refreshed. A new request will be sent again.

**‌Triggered Event:** ‌If specified, an event with the specified name will be triggered once the data load was triggered.

### Fetch

The Fetch Settings determine the source and the method for retrieving the External Data

**Data Source Type: ‌**Specifies a source type from which data will be fetched. Available options: URL, IndexedDB.

<mark style="background-color:yellow;">Settings when</mark> <mark style="background-color:yellow;">**URL**</mark> <mark style="background-color:yellow;">is selected</mark>

**‌Data Source URL:** The API endpoint to which a request is made to retrieve data.

**‌Method: ‌**The method to be used when making a request to the specified endpoint. Available options: GET, POST.

**‌Request Headers: ‌**HTTP request headers to be used when making a request to the specified endpoint.

**‌Forward Headers:** Forwards the headers passed to the server to the fetch endpoint.

**​Form.io Authentication: ‌**Passes Form.io Authentication headers with the request.

**​Enable To Store Request Result in the Cache: ‌**If checked, the result of each API call to the specified endpoint will be cached. That means, if the Data Source refresh is triggered again with the same URL, it won't make a real request to that URL, but rather take the result of the previous request with the same URL from the cache.

*Uncheck this setting, if the returned data from the URL updates frequently and should be kept up-to-date.*

<mark style="background-color:yellow;">Settings when</mark> <mark style="background-color:yellow;">**IndexedDB**</mark> <mark style="background-color:yellow;">is selected</mark>

**Choose From Existing Databases?:** Allows selecting an existing database.

**Database Name:** The name of the indexedDB database.

**Table Name:** The name of a table in the indexedDB database.

**Existing Database Name:** The name of the existing indexedDB database.

**Existing Table Name:** The name of an existing table in the indexedDB database.
{% endtab %}

{% tab title="Guidance" %}
**U‌se Cases:**

* Perform custom validation based on external data

  [**Click Here** ](/how/data-source-validation)for examples
* Use the Data Source with other components like text fields, to display external information to the form user.
* Save external data in the submission for future use or calculations (e.g. currency exchange rate at the moment of submission)
  {% endtab %}

{% tab title="Examples" %}
**Populating Data From An External URL**

The following examples connect the DataSource component to an API URL listing the USA States. Use the Embed URLs to copy these example forms into your project.

* Show State by the entered abbreviation using Data Source

  **Form Embed URL:** [**https://gtbvdrunldplvre.form.io/datasourceexample1**](https://gtbvdrunldplvre.form.io/datasourceexample1)
* Show States Abbreviations Cheat Sheet using Data Source\
  **Form Embed URL:** [**https://gtbvdrunldplvre.form.io/datasourceexample2**](https://gtbvdrunldplvre.form.io/datasourceexample2)
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Data Source",
  "persistent": "client-only",
  "trigger": {
    "init": false,
    "server": false
  },
  "refreshOn": "populate",
  "event": "fetchMe",
  "dataSrc": "url",
  "fetch": {
    "url": "https://myurl.json",
    "method": "get",
    "headers": [
      {
        "key": "",
        "value": ""
      }
    ],
    "mapFunction": "",
    "forwardHeaders": false,
    "authenticate": false
  },
  "allowCaching": true,
  "key": "dataSource",
  "type": "datasource",
  "input": true,
  "tableView": false
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

## CAPTCHA

**What is the CATPCHA component?**

The Form.io CAPTCHA component is used to integrate CAPTCHA service providers into Form.io forms. CAPTCHA is a security measure designed to differentiate between human users and automated bots, helping to protect forms from spam and abuse.

<figure><img src="/files/ePVNzb8icOUBU3iu4ZHl" alt="" width="556"><figcaption></figcaption></figure>

**How do I use the CATPCHA Component?**

To use this component, you'll need to configure CAPTCHA with one of the supported providers:

* [**Cloudfare Turnstile**](https://developers.cloudflare.com/turnstile/)
* [**Goolge reCAPTCHA**](https://developers.google.com/recaptcha/docs/v3)

After configuring a provider, copy the **Site Key** and **Secret Key**, then integrate these credentials into your project settings.

1. Navigate to your Project Settings > Integration > CAPTCHA
2. Specify the Site Key and a Secret Key from your provider
3. Save the Settings

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

As a result, your project will contain the following JSON:

```
 "settings": {
   "captcha": {
     "secretKey": "your_secret_key",
     "siteKey": "your_site_key"
   }
 }
```

Once the integration is complete the component will be available to add to your forms.

1. Drag and drop the **CAPTCHA** component on your Form
2. Within the component **Settings**, select the **CAPTCHA Provider**
3. Select whether the reCaptcha should execute when the **Form Loads** or **Trigger on button click**.
4. **Save** your **Settings**

{% hint style="warning" %}
When using a CAPTCHA component on a form configured as a [Wizard](#dynamic-wizard), the CAPTCHA **must** be placed on the final page of the wizard. Using a CAPTCHA component on prior wizard pages may prevent the form from submitting.
{% endhint %}

When the CAPTCHA is executed and the form is submitted, the CAPTCHA results can be found in the metadata of the submission.

**Render From JSON**

If you want to render the form with a CAPTCHA component from JSON, add the following:

1. Add the following settings to the Form JSON:

   ```
    {
        "settings": {
            "recaptcha": {
                "isEnabled": "true",
                "siteKey": "your_site_key"
            }
        }
    }
   ```
2. Before the form is rendered, set the Project URL to the URL of project you have your CAPTCHA Secret Key set:

   ```
    Formio.setProjectUrl('<your_project_URL'); //for ex. https://examples.form.io/
   ```

You can now render the form using JSON:

```
Formio.createForm(document.getElementById('formio'), 'your_form_json').then(function(form) {
  // Provide a default submission.
  form.submission = {
    data: {
    }
  };
});
```

### Unique Settings

**CAPTCHA Provider:** Select the provider integrated into your project:\
\
\&#xNAN;***Google reCAPTCHA:*** Utilizes [**Google's reCAPTCHA v3**](https://developers.google.com/recaptcha/docs/v3) which returns a score for each request without user friction. The score is based on interactions on your form and can help determine if the score represents a human or malicious interaction. The reCaptcha results can be found in the metadata of the submission.

```
      "challenge_ts": "2019-01-11T10:29:39Z",
      "hostname": "your_domain",
      "score": 0.9,
```

\
\&#xNAN;***Cloudfare Turnstile:*** Upon submission, [**Cloudflare Turnstile CAPTCHA**](https://developers.cloudflare.com/turnstile/) returns a cryptographically secured token within the metadata of the submission object. This token is sent with the form data, allowing the server to interpret and validate it to help protect against automated spam and abuse

{% code lineNumbers="true" %}

```
      "token": "0.CAPTCHATOKEN-ZGg_8ytlSUI6K4e4s9"
```

{% endcode %}

**Type of Event:** Sets the type of event to which the CAPTCHA component would react to: Button Key, Form Load

***Trigger on Form Load:*** When your form with Form Load CAPTCHA triggers a ‘formLoad’ event, a verification request is sent to the CAPTCHA provider for an action called ‘\<your\_form\_name>Load’. The data object in the submission response will vary depending on the provider.

*E.G. Google’s reCAPTCHA submission value response*

```
{
  "data": {
    "reCaptcha": { 
      "success": true,
      "challenge_ts": "2019-01-11T10:29:39Z",
      "hostname": "your_domain",
      "score": 0.9,
      "action": "<your_form_name>Load" 
    }
  }
}
```

***Button Key**:* Select the Button on the form that the CAPTCHA component will react to.

*This is only allowed when the Button action is set to Event .*

**Trigger on Button Click**

When any button on your form is clicked, the renderer searches for a Button Click CAPTCHA component associated with the same API key as the clicked button. If the renderer finds this CAPTCHA component, it sends a verification request to the provider for an action called '\<your\_button\_key>Click'. The provider's response then becomes the submission value of your Button Click reCAPTCHA component.

*E.G. Google’s reCAPTCHA Button Click response*

```
{
  "data": {
    "reCaptcha": { 
      "success": true,
      "challenge_ts": "2019-01-11T10:29:39Z",
      "hostname": "your_domain",
      "score": 0.9,
      "action": "<your_button_key>Click" 
    }
  }
}
```

**Trigger on Button Click**

When any button on your form is clicked, the renderer searches for a Button Click CAPTCHA component associated with the same API key as the clicked button. If the renderer finds this CAPTCHA component, it sends a verification request to the provider for an action called '\<your\_button\_key>Click'. The provider's response then becomes the submission value of your Button Click CAPTCHA component.

**Visible Verification (Cloudfare Turnstile):** If selected, space will be allocated for the Cloudflare Turnstile CAPTCHA widget to appear on the form and will create white space for the widget while the form is loading.

### Guidance

Use the reCaptcha component to protect your forms from bot spamming and malicious activity.

### Example

An example of reCaptcha used on a form can be found on the [Form.io GitHub](http://formio.github.io/formio.js/app/examples/recaptcha.html).

### JSON

```
{
  "key": "recaptcha",
  "type": "recaptcha",
  "input": true,
  "tableView": false,
  "label": "reCAPTCHA"
}
```

## File

**What is the File component?**

A File component allows form users to upload and download files to a form. In order to use the File component, file storage must be set up in the project settings. See the [**File Storage**](/dev/integrations/file-storage) help topic for the list of supported file storage providers.

**How do I use the File component?**

Form.io does not host any files uploaded through a form response. Instead, files are stored with the Storage Provider selected for the component. Form.io will store references to the files, enabling access to the file through the Storage Provider, and further integration of those files into the application.

Before a provider can be selected within the component, the file storage provider must first be integrated into the Form.io project. Refer to the [**File Storage**](/dev/integrations/file-storage) help topic for more detailed instructions on establishing File Storage.

Once a storage provider has been set up, it should be selectable within the File component **Storage** settings. Additional settings such as file display, enabling webcam for mobile devices, and file type validations can be set.

When embedding the file component in an application make sure to set the baseUrl and projectUrl on the Formio object. This allows the file component to know the location of the formio-server so it can generate a file upload URL.

**How does file upload work?**

The file component upload works by taking the projects file storage integration settings and generating a temporary URL that allows the client to upload file to the storage provider. Below is a detail flow diagram on how this works.

<figure><img src="/files/esKn0r6Hzx1Jm25pUVWQ" alt="" width="375"><figcaption></figcaption></figure>

1. The **browser** makes a POST request to /{project\_alias}/form/{form\_alias}/storage/{storage\_provider} with metadata about the file
2. The **Formio Server** verifies that the user has the permissions to upload a file based on the **forms submission permissions.** If the user has proper permissions then the server generates a URL with a temporary token attached as a query parameter. This token is what allows clients to upload files without needing a secret access key. This URL is then sent back to the **browser**
3. The **browser** receives the URL from the **Formio Server** and makes a PUT request with the file contents to the **file storage server** to upload the file.

{% hint style="info" %}
Because the URL to upload the file is generated on the server, the **secret access key** to your storage provider is **never** exposed to the client. This allows allows the client to upload the file instead of the server, reducing the networking load on the server and mitigating the risk of malicious files being uploaded.
{% endhint %}

**How do I set file CRUD permissions?**

Permissions for creating, reading, and deleting files in the file component are managed through submission permissions. The following permissions correspond to what users can do with files:

* Create Submission - Allows for uploading files
* Read Submission - Allows for viewing the files
* Delete Submission - Allows for deleting the files
  * In order to allow unauthenticated users to delete files when using an embedded form, the Delete Own Submissions permission may need to include the Anonymous role.

Refer to [**Submission Permissions**](/admin/roles-and-permissions#submission-data-permissions) for additional details.

**How are files managed?**

When the form user selects a file for upload, it is immediately sent to the configured storage provider, regardless of whether the form is submitted or not. The file will remain in storage even if the form user removes the attached file.

{% hint style="info" %}
Beginning with Formio-Enterprise 9.3.0, when the form user removes the attached file, the file is deleted from storage.
{% endhint %}

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

{% tabs %}
{% tab title="Unique Settings" %}

### **Storage**

The storage providers which the file will be stored and accessed from. Select the appropriate provider. All providers (excluding URL and IndexedDB) require integration configurations to be set up in the project settings:

* **Base64:** Files are locally stored in the browser. This should only be used for testing purposes.
* [**S3**](/dev/integrations/file-storage#s3): File storage and retrieval using any S3 compatible service, specifically designed for Amazon Web Services S3.
* [**URL**](/dev/integrations/file-storage#custom-url): Set up a self-hosted solution, or use an existing service that can upload and serve files. For more information on how to set up the server, consider the [ng-file-upload documentation](https://github.com/danialfarid/ng-file-upload#server-side).
* [**Azure File Services**](/dev/integrations/file-storage#azure-blob): Upload files from hosted forms directly to an Azure Blob storage.
* **IndexedDB:** Upload files to a predefined IndexedDB API.
* [**Google Drive**](/dev/integrations/file-storage#google-drive): Upload files to an integrated Google Drive platform.
* **CSV** - INFO COMING SOON.

The following settings may be available depending on which Storage provider is selected:

* **Private Download:** Makes the file download send a POST request to the download URL with the *x-jwt-token* header. This will allow an endpoint to create a private download system.
* **Custom Request Options:** Allows passing the custom xhr options.
* **File Form-Data Key:** Key name that is used to modify for the file while calling API request.
* **Database:** The name of the IndexedDB database.
* **Table:** The name of a table in the IndexedDB database.

### Additional Settings

**Directory:** This field appends all files with a string so that they are in a directory on the storage provider. Must end in “/”.

**File Name Template:** Specifies a template for the name of the uploaded file(s). Regular template variables are available (`data`, `component`, `user`, `value`, `moment`, etc.). The variables `fileName and` `guid` are also available. The `guid` part must be present and will be added automatically if not found in the template.

**Upload Only:** Disables the download option and allows only the upload of files.

**Display As Image(s):** Instead of a list of linked files, images are rendered in the view.\
The filter in the file explorer will be set to the **Image Files** type on upload.

**Image Size:** The image size in pixels for previewing images.

**Enable Web Camera:** Allows using an attached camera to directly take a picture instead of uploading an existing file.

**Webcam Width:** The webcam size in pixels for taking pictures.

**File Types:** Allows specifying file types to classify the uploads. This is useful when allow multiple types of uploads but want to allow the user to specify which type of file each is.

**File Pattern:** Dictates which file extensions will be allowed to upload. Files not specified in this field will be prevented from being uploaded.

For more information on how to specify file patterns and sizes, refer to the [ng-file-upload documentation](https://github.com/danialfarid/ng-file-upload#server-side).

**File Minimum/Maximum Size:** Allows setting a minimum/maximum file size for uploaded files.

**File Maximum Size:** Allows setting a maximum file size for uploaded files.
{% endtab %}

{% tab title="Field Examples" %}

{% endtab %}

{% tab title="Guidance" %}

{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Upload",
  "tableView": false,
  "storage": "",
  "webcam": false,
  "fileTypes": [
    {
      "label": "",
      "value": ""
    }
  ],
  "key": "file",
  "type": "file",
  "input": true,
  "options": {}
}
```

#### Specific Properties

<table><thead><tr><th width="156">Property</th><th width="252">Description</th><th>Value</th><th>Required</th><th>Default</th></tr></thead><tbody><tr><td>image</td><td>If this file component should be used for managing images</td><td>boolean</td><td><code>false</code></td><td><code>false</code></td></tr><tr><td>imageSize</td><td>If this file component is configured as an image upload, then the size of images that are shown when uploaded.</td><td><code>string</code></td><td><code>false</code></td><td><code>200</code></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

## Nested Form

**What is a Nested Form?**

The Nested Form component inserts an existing Form or Resource (the *child form)* into another Form or Resource (the *parent form*). All fields contained within the child form, including all field settings, will display accordingly in the Parent form.

For detailed help, refer to the [Nested Form](/form-building/nested-forms) deep-dive document.

**Using Nested Forms**

Once the child form has been created within the same project, simply drag and drop the Nested Form component onto the parent Form and select the child Form or Resource. The Nested Form component will display as an empty component in the builder, but will display the child Form fully when rendered.

Nested forms may themselves contain nested forms. The maximum depth of nested forms is 3. The platform will not process submissions from a form greater than 3 levels away from the parent form.

**Nested Forms For Remotely Deployed Projects**

If your project is remotely deployed with subdirectories, set up your application to perform an API call like the following:

```
 Formio.setProjectUrl(<project_URL>). 
```

This will help Form.io understand where to fetch nested resources from and will set up base URLs properly.

{% tabs %}
{% tab title="Unique Settings" %}
**Form:** Select a child Form/Resource that you’d like to nest into the parent form

**Save as reference:** Check if you’d like to save only \_id of the child form submission instead of storing all child submission object inside of parent submission. This will also help all changes you’ve made in child submission be reflected in parent submission. If not checked, the entire child submission object will be saved. Any updates or changes made to the child submission data will not be reflected in the parent submission. Refer to the [appropriate section](https://app.gitbook.com/s/6LdEf8SjBIeQDsRL3BdV/components/premium-components/using-nested-forms) of the Nested Forms deep-dive document for additional information and guidance.
{% endtab %}

{% tab title="Field Examples" %}

{% endtab %}

{% tab title="Guidance" %}
Nested forms may themselves contain nested forms. The maximum depth of nested forms is 5. The platform will not process submissions from a form greater than 5 levels away from the parent form.
{% endtab %}

{% tab title="JSON" %}

{% endtab %}
{% endtabs %}

## Tagpad

**What is the Tagpad?**

The Tagpad component allows the form designer to add an image URL to the component. Additional components, like a Text Field, can then be added to the Tagpad image. This allows form users to 'tag' a point on the image and input data associated with the tagged point. Tagged points and corresponding input data will be saved with the submission data when the form is submitted.

**How do I use the Tagpad?**

{% hint style="info" %}
Use a publicly accessible image when using the Tagpad.
{% endhint %}

Inside the Form Builder, drag and drop the Tagpad component from the Premium component grouping onto the form. Within the Tagpad settings, copy and paste your image URL to the corresponding field. Once set, the image will display in the Preview section of the component settings.

<figure><img src="/files/ou3YWY7k0in2BNIsgEk2" alt=""><figcaption><p>Tagpad Settings</p></figcaption></figure>

After adding your image URL, use the form builder to add additional components inside the Tagpad drop-zone.

<figure><img src="/files/F9BpzJTrCVOfoq4tRGAt" alt=""><figcaption><p>Add components inside the Tagpad</p></figcaption></figure>

These components will display for the user when an area is 'tagged' on the image. The form user can then input field data to the corresponding dot tag which will be saved with the submission. Add as many dot tags as needed to the image. View or update input values for any saved dot by clicking the dot. Remove a dot tag and corresponding data by clicking the red trash can icon.

<figure><img src="/files/qN1hae6N6hmemMsT6R5i" alt=""><figcaption><p>End user interacting with the Tagpad component</p></figcaption></figure>

{% embed url="<https://drive.google.com/file/d/14RaJw9Pzonr_Mafz2zo-fElah5HBbmur/view?usp=sharing>" %}
Tagpad visual guide
{% endembed %}

{% tabs %}
{% tab title="Unique Settings" %}
**Width:** Default image width

**Height:** Default image height

**Dot Size:** Default size of the dot tag

**Dot Size Stroke:** Default dot tag border width

**Dot Stroke Color:** Default dot tag border-color configured using [**HEX**](https://www.color-hex.com/) color identifier

**Dot Fill Color:** Default dot color set configured using [**HEX**](https://www.color-hex.com/) color identifier

**Dot Custom Label:** Default label of the dot tag

**Dot Value Template:** The HTML template representing the Dot values tagged by the form user. This template can be modified within the **Template** tab within the Tagpad settings. There are four variables that can be modified within the template:

* **Dot:**
* **Index:**
* **Array:**
* **Instance:**
  {% endtab %}

{% tab title="Guidance" %}
Use the Tagpad component when input data is needed represented by a visual dot tag on an image. Some common use cases for the Tagpad:

**Healthcare Forms**

**Vehicle Fleet Inspection**

**Construction Compliance**

**Home Inspection Reports**

**Case Reporting**
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Tagpad",
  "imageUrl": "https://myimageurl.jpeg
  "tableView": false,
  "key": "tagpad1",
  "type": "tagpad",
  "input": true,
  "components": []
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

## Sketchpad

**What is the Sketchpad?**

The Sketchpad allows a form designer to add a public image to the Sketchpad component. End users interacting with the form can then sketch on the image using a WYSIWG-type editor. Sketches made on the drawing will be saved with the submission data when the form is submitted.

**How do I use the Sketchpad?**

{% hint style="info" %}
Use a publicly accessed image when using the Sketchpad
{% endhint %}

Start by dragging over the Sketchpad component from the Premium component grouping onto the form. Within the Sketchpad settings, copy and paste your image URL to the corresponding field. Once set, the image will display in the Preview section of the component settings and on the form builder.

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

Once set, end users interacting with the form can click the image to open a module. Here the user can perform different actions like drawing on the image, adding object shapes, changing line thickness, and selecting the sketch color. These settings are controlled by the end user inside the module window. The form designer can also change the default values for the mentioned settings.

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

{% embed url="<https://drive.google.com/file/d/1yR2Hs_PMlLnDSqTrZAzumyoO7tvh-aB5/view>" %}
Sketchpad Visual Guide
{% endembed %}

{% tabs %}
{% tab title="Unique Settings" %}
**Image URL:** Image that will display on the Sketchpad component

**Set Size Automatically:** The form renderer automatically sizes the image based on available form space

**Default Zoom:** How close or far the image will appear to the form user

**Default Stroke Color:** Default color of the drawing strokes using [**HEX**](https://www.color-hex.com/) color identifier

**Default Fill Color:** Default color of the shape fills using [**HEX**](https://www.color-hex.com/) color identifier

**Default Line Width:** Default width of the line strokes

**Default Circle Size:** Default line width of the circle shape
{% endtab %}

{% tab title="Guidance" %}
Use the Sketchpad component when a drawn visual representation is needed on an image from the form user. Some common use cases for the Sketchpad:

**Healthcare Forms**

**Vehicle Fleet Inspection**

**Construction Compliance**

**Home Inspection Reports**

**Case Reporting**
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Sketchpad",
  "imageUrl": "https://myimageurl.svg",
  "tableView": false,
  "key": "sketchpad",
  "type": "sketchpad",
  "defaultLineWidth": 5,
  "input": true
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

## Review Page

**What is the Review Page?**

The Review Page component presents form users with a summary of their data before submitting the form. This component is code free and simple to configure, catering to non-developer users.

**How do I use the Review Page?**

The Review Page populates data from components that have already been added to the form. To set up the Review Page:

1. Add other components to the Form as needed.
2. Drag and drop the Review Page from the Premium Component group
3. Open **Settings** for the Review Page component, then click the **Review Fields** dropdown.\
   This dropdown lists all of available fields within the form.
4. Select any *single* *input* field from the available components to add it to the list of fields that will be presented on the review page. The selection order of the components determines the order they appear on the Review Page.

{% hint style="info" %}
Some complex components contain multiple input fields. If the form contains Data Grid, Data Table, Data Map, Edit Grid or Survey components, then the containing components are selectable for review, though the individual fields within that component are **not.**
{% endhint %}

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

Once the Review Page is configured, use the form to test out the summary. As the form is filled out, the Review Page outputs the data of the selected fields to the Summary section of the component.

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

**Why should I use the Review Page?**

Using the Review Page is a great way to give form users a chance to review their data before submitting the form, which can help reduce user errors and make for a better user experience.

{% tabs %}
{% tab title="Unique Settings" %}
**Review Fields:** Multi-Select dropdown that will populate all of the available fields within your form. Select any single input field from the list. The selection order of the components will also dictate the order they appear on the Review Page.
{% endtab %}

{% tab title="Guidance" %}

* If you are utilizing PDF downloads, it may not be beneficial to have the Review Page part of the output. To remove the Review Page from the PDF download, simply move the Review Page component inside a [**Panel**](/form-building/layout-components#panel) and add the following [**Field Tag**](/form-building/component-settings#field-tag) to the Panel settings `viewer:hide`. This will include the Review Page when a user is filling out the Form, but remove the component when viewing the PDF Download.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Review Page",
  "type": "reviewpage",
  "input": true,
  "key": "reviewPage",
  "tableView": false,
  "tag": "div"
}
```

{% endtab %}
{% endtabs %}

## Custom

Custom components allow users to create a custom field using the JSON schema of other component types. When complete, these custom components will be rendered using a front-end application. This is a very useful and flexible option to create special or complex form fields that might not be offered with the out-of-the-box form builder.

To use a custom component, create a JSON definition of the field with the information needed to render it. Create a custom field and paste the JSON object into it. This must be a valid JSON object.

```
{
  "type": "custom",
  "isNew": true,
  "key": "custom",
  "protected": false,
  "persistent": true
}
```

There are several properties that are required but **you may add any additional properties that you would like**.

![](/files/HjghCOjTNY5SFVIjP6K8)

{% tabs %}
{% tab title="Custom JSON Elements" %}
**Type:** The type property will be used to select which component to render on the front end. It cannot be an existing field type.

**Key:** The key field is where the data will be saved to. This must be unique per field. For example, if `key = 'customers'` then the value of the field will be saved in `data.customers`.

**Persistent:** This will determine whether or not the value is saved to the main database. This is useful for using Remote Middleware, verify password fields or sending the data in an action but not saving it.

**Protected:** This will determine whether or not the field will be visible from the API. If it is a protected field then it will only be writable but not readable.

**Rendering:** In order to render the custom component, the front-end application must register the component template. This is done in the config step with the formioComponentsProvider.

```
app.config([
  'formioComponentsProvider',
  function (formioComponentsProvider) {
    formioComponentsProvider.register('checkmatrix', {
      title: 'Check Matrix',
      template: 'formio/components/check-matrix.html',
      settings: {}
    });
	}
]);
```

The template will then be used to render the component. In addition, a controller may be added to the template to create more interactive form elements.

This is a working example of a custom component. It is a Matrix checkbox that changes the number of columns and rows based on two other form fields.**Type:** The type property will be used to select which component to render on the front end. It cannot be an existing field type.

**Key:** The key field is where the data will be saved to. This must be unique per field. For example, if `key = 'customers'` then the value of the field will be saved in `data.customers`.

**Persistent:** This will determine whether or not the value is saved to the main database. This is useful for using Remote Middleware, verify password fields or sending the data in an action but not saving it.

**Protected:** This will determine whether or not the field will be visible from the API. If it is a protected field then it will only be writable but not readable.

**Rendering:** In order to render the custom component, the front-end application must register the component template. This is done in the config step with the formioComponentsProvider.

```
app.config([
  'formioComponentsProvider',
  function (formioComponentsProvider) {
    formioComponentsProvider.register('checkmatrix', {
      title: 'Check Matrix',
      template: 'formio/components/check-matrix.html',
      settings: {}
    });
	}
]);
```

The template will then be used to render the component. In addition, a controller may be added to the template to create more interactive form elements.

This is a working example of a custom component. It is a Matrix checkbox that changes the number of columns and rows based on two other form fields.
{% endtab %}
{% endtabs %}

## Data Table

The Data Table enables the user to fetch large sets of data from external sources and present that data to the end-user in a table format. Think of the Data Table as an advanced select component, allowing the form designer to specify which data points from the external data object source should appear as selectable rows within the table for end-users.

<details>

<summary>Select Field &#x26; Data Table Comparison</summary>

The Data Table and Select component are both utilized in similar ways. Each component can fetch data from external sources and present that data to the end-user as selectable options. The following example will highlight the difference between the two and why the Data Table might be a better solution for your use case.

Both components in this example are fetching data from the identical 'Department' Resource, which contains four distinct fields

Department ID | Department Name | Building Number | Email

When using a [**Select**](/form-building/basic-components#select) component, the form designer can fetch data from a Resource, however, only one data point from the Resource submission object can be used as the Select value. In the screenshot below we can see the Select component connected to the Department Resource and the form designer is limited to choosing one value that will display for the component.

<img src="/files/DAZGvEN75EhVV2B0oCyB" alt="" data-size="original">

The benefit of using the Data Table is the component can still fetch from a Resource, however, the form designer can choose which fields (or data points) will display for the end-user as the selectable option. This allows the user to make a more informed decision when selecting an option. The screenshot below shows the Data Table fetching data from the same Department resource, however, all four Resource data points are presented to the user as a selectable option.

</details>

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

{% hint style="info" %}
The Data Table included within a form is intended for incorporating data from an external data source and presenting that data to the end-user as selectable options that can be sent to the server upon submission.

If you are looking for a visualized report displaying data from multiple form sources in a table grid format with pagination, filtering, and sorting capabilities, please see the [**Form.io Reporting Module**](/dev/form.io-reporting-module) documentation.
{% endhint %}

{% tabs %}
{% tab title="Unique Settings" %}
*Some settings will be added or removed depending on if the Fetch setting is enabled.*

## Data Table as a Select Component

The Data table will fetch and present external data within the data table as selectable options for the end user. The Fetch Settings determines the source and method for retrieving external data that will populate within the Data table. When Fetch is enabled, data will **not** submit to the server unless configured to only submit rows selected by the end user.

**Enable Fetch:** If fetch is enabled, the DataTable will retrieve data from an external source.

**Fetch Source Type:** Retrieve the data from an internal Resource or external URL.

**Submit Selected Rows:** When the *Submit Selected Rows* option is enabled, the user can select the Data Table rows by clicking the row checkbox. The selection remains persistent across filtering, sorting, changing items per page, and pagination. After the form is submitted, only the data of the selected rows will be sent to the server.

### Fetch Resource

Settings when Fetch Resource is enabled

**Fetch Resource:** Fetches submission data from internal Resources within your project.

**Resource:** The resource to be used to populate the data in the data table.

**Components:** Select the Resource fields that will display for the option row of the Data Table. Use the +Add Component button to add additional fields to the option row.

**Default Sort Query:** This sort query is used if the data table column sorting is not set.

**Enable to Store Request Result in the Cache:** Enabled by default, this setting stores requests and their results within the browser cache. When the Data Table attempts to request data from the same URL with identical parameters, cached data will be returned, enhancing performance. This option should be disabled If the data from the data source frequently changes and requires constant updates.

### Fetch URL

Settings when Fetch URL is enabled

**Data Source URL:** A URL that returns data. You can interpolate form data using curly bracket notation.

**Request Headers:** Set any headers that should be sent along with the request to the URL. This is useful for authentication.

**Transform Data:** Write custom code to transform DataSource data.

**Form.io Authentication:** When checked, Form.io authentication headers are added to the request to ‘Data Source URL’. Mainly used if Data Table data is requested from a Form.io endpoint.

**Custom Fetch Provider:** The name of a custom fetch provider. If not specified, the default URL provider is used

**Default Sort Query:** This sort query is used if the data table column sorting is not set.

**Enable to Store Request Result in the Cache:** Enabled by default, this setting stores requests and their results within the browser cache. When the Data Table attempts to request data from the same URL with identical parameters, cached data will be returned, enhancing performance. This option should be disabled If the data from the data source frequently changes and requires constant updates.

***

**Sortable:** Sort columns in ascending/descending order.

**Filterable:** Selectively display rows of data based on specific criteria or conditions. Provided filter operations such as "contains", "matches", "less than", "greater than", "equals", "not equals" and etc

**Cell Max Width:** Set the static width of the Data Table column width.

**Clip Cells:** Truncates data in a cell if it exceeds the width available within the column

**Items Per Page:** Set the default rows of data per page.

## Data Table as 'Add Another' input component

While not the primary use case of the Data Table, when Fetch is disabled, fields can be added to the Data Table for user input with 'Add Another' functionality.

Because the Data Table includes pagination, filtering, and sorting capabilities, it is not recommended for most 'Add Another' use cases, we suggest utilizing the [**Edit Grid**](/form-building/data-components#edit-grid) or [**Data Grid**](/form-building/data-components#data-grid)**.**

**Inline Editing:** Actively edit the input fields without requiring the user to open the Data Table modal.

**Show Add Button:** Displays the button to add a new input row to the table.

**Show Edit Button:** Enables the user to edit an input row

**Show Delete Button:** Enables the user to delete an input row

**Show Delete All Button:** Enables the user to delete all input rows within the table.
{% endtab %}

{% tab title="Use Case Examples" %}

## Fetch Resource

This example will showcase how to use the Data Table to fetch data from an internal Resource within your Project. The Data Table will be configured to present the end-user with certain data points from the submission object of the connected Resource. The end-user can then select option rows within the data table that will be sent to the server upon submission.

A Department Resource will be created with fields representing different Department data points (Department ID, Name, Building Number, Email). Submissions will be made against the Resource to establish the Department database. The Data Table will be configured to fetch the submission data from the Department and present that data to the end user as selectable options.

#### Resource Data

1. Create a **Resource** called **Department**
2. Make submissions against the Resource to create a Department database

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

#### Configure Data Table

1. Add a Data Table to the form
2. Click the **Fetch** tab and check the **Enable Fetch** setting
3. Select **Resource** as the Fetch Source Type
4. Select **Department** from the Resource list

<figure><img src="/files/2qwfBMz6KNsXoFHzukC8" alt="" width="427"><figcaption></figcaption></figure>

5. Click the **+Add Component** button to add fields from the Resource to the Department. These fields will represent the different data point options from the Resource submissions the end-user can choose from.

<figure><img src="/files/Iin6tdMNTXcIxLvdbQe3" alt="" width="427"><figcaption></figcaption></figure>

6. Click the **Data** tab and check the **Submit Selected Rows** setting.

#### Submit the Data Table

7. **Use** the form to view the Data Table and select different options

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

By default, when Fetch is enabled, the Data Table will not submit data to the server. Enable the **Submit Select Rows** setting to allow the selected rows to be submitted and saved to the server.

8. Click the **Data** tab and check the [**Submit Selected Rows**](#user-content-fn-1)[^1] setting

Use different settings from the Display tab to configure the data table for sorting and filtering or choose how many option rows display per page of the table.

<figure><img src="/files/2teI4Leqe7ypluJwL9Pl" alt="" width="420"><figcaption></figcaption></figure>

## Fetch URL

This example will showcase how to use the Data Table to fetch data from an external URL and output the data to a table. The end-user can then select option rows within the data table fetched from the URL that will be sent to the server upon submission.

1. Add the Data Table to a form
2. Click the **Fetch** tab and check the **Enable Fetch** setting
3. Select **URL** as the Fetch Source Type
4. Add the **Data** **Souce** **URL**. This endpoint will return the data object of US States.

[https://cdn.rawgit.com/mshafrir/2646763/raw/states\_titlecase.json](https://gists.rawgit.com/mshafrir/2646763/raw/states_titlecase.json)

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

You may have noticed the data rows populating without the data fields. Manually add fields to map the incoming data.

5. Add a TexField called **Name** and ensure the **API** **Property** **Name** is `name`
6. Add a TextField called **Abbreviation** and ensure the API Property Name is `abbreviation`

The API Property Names of the TextFields match the JSON names to ensure data will map and populate correctly within the Data Table.

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

7. Click the **Data** tab and check the **Submit Selected Rows** setting.
8. Use the Form to view the Data Table and select different options

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

## Data Table as 'Add Another' input component

While not the primary use case of the Data Table, when Fetch is disabled, fields can be added to the Data Table for user input with 'Add Another' functionality. Because the Data Table includes pagination, filtering, and sorting capabilities, it is not recommended for most 'Add Another' use cases, we suggest utilizing the [**Edit Grid**](/form-building/data-components#edit-grid) or [**Data Grid**](/form-building/data-components#data-grid)**.**

To use the Data Table as an 'Add Another' user input component, simply ensure **Fetch** is disabled from the settings and add the desired components inside the Data Table

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

When the form is rendered, the end-user can add a new row to the Data Table by clicking the + button. A modal will display prompting the user to input data.

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

Once the modal window has been saved, the input data will display as a row within the Data Table. From here, the user can add a new row of data or edit and delete an existing row.

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

Checking the **Inline Edit** setting allows the user to dynamically update the data within the row without clicking the edit button and modifying the data via the modal window.

<figure><img src="/files/rz1zietOVDL23UHBZzKX" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## **Dynamic Wizard**

A Dynamic Wizard allows you to collect an array of object values and then saved data is output to a table view as new rows are added. Filling an array element (field) occurs in steps, where each component inside the Dynamic Wizard is a separate step.

The principle of operation is based on the behavior of the Wizard. However, when you click the next step button, the current page of the Wizard remains the same until you have progressed through all of the fields within the Dynamic Wizard. The table view of the filled data appears with the successful passage of the last step, or when you click on the cancel button.

{% hint style="info" %}
As of server version **9.3.0**, the Dynamic Wizard has been migrated to the community contrib repository. [**Click Here**](https://github.com/formio/contrib/tree/master/src/components) to access the repository for information on installation and integrating the Dynamic Wizard component into the Form.io Platform.
{% endhint %}

[^1]: When enabled, the data of the selected rows will be submitted to the server


# Data Components

Using and configuring Data Components in the Form Builder

Data components are fields that manipulate the way Data is presented, saved, and organized.

{% embed url="<https://youtu.be/AEZPPAW9zAU>" %}

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Hidden</strong></td><td>Execute logic or workflows behind the scenes with the Hidden component</td><td></td><td><a href="#hidden">#hidden</a></td></tr><tr><td><strong>Container</strong></td><td>Add components to a Container to save the field set as an Object.</td><td></td><td><a href="#container">#container</a></td></tr><tr><td><strong>Data Map</strong></td><td>Create Key/Value pairings.</td><td></td><td><a href="#data-map">#data-map</a></td></tr><tr><td><strong>Data Grid</strong></td><td>Add an rows of field groupings.</td><td></td><td><a href="#data-grid">#data-grid</a></td></tr><tr><td><strong>Edit Grid</strong></td><td>Add Field Sets and customize how the Grid saves and displays the row</td><td></td><td><a href="#edit-grid">#edit-grid</a></td></tr></tbody></table>

### Hidden

The Hidden component is used to include data in a form that is not visible to users but is submitted with the form data. It's often used for purposes such as storing metadata, user information, or default values that should not be modified or seen by the user. While there is no front-end widget or display for hidden components, the component will be visible within the form builder to access the component settings where data calculations and logic can be configured. These calculations or logic can be utilized to facilitate more advanced workflows on your form or application.

{% tabs %}
{% tab title="Unique Settings" %}
There are no unique settings for the Hidden component
{% endtab %}

{% tab title="Guidance" %}

* Use hidden components to contain **Calculated Values** for use in workflows and [**Logic**](/form-building/logic-and-conditions) within your application or form.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Hidden ",
  "key": "hidden",
  "type": "hidden",
  "input": true,
  "tableView": false
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Container

A Container is a hidden wrapper that is used to group other form components together within a form. What makes the Container unique to the other Layout components is how it stores component data. The components inside the Container are grouped into an object under the Container's API Property key and are saved within the metadata structure of the submission. This feature is particularly useful for creating more complex objects and data sets within your form.

{% tabs %}
{% tab title="Unique Settings" %}
There are no unique settings for the Container component
{% endtab %}

{% tab title="Guidance" %}

* Coming Soon...
  {% endtab %}

{% tab title="JSON" %}
**Component Schema**

```
{
  "label": "Container",
  "tableView": false,
  "key": "container",
  "type": "container",
  "input": true,
  "components": []
}
```

**Data Map Data Structure:** userInformation being the Container key

```
{
 data: {
    userInformation {  
      firstName: “Joe”,
      lastName: “Smith”,
      email: "joe@example.com"
    }
  }
}
```

#### Specific Properties

<table><thead><tr><th>Property</th><th width="335">Description</th><th width="84">Value</th><th width="94">Required</th><th>Default</th></tr></thead><tbody><tr><td>tree</td><td>Determines if the Validation should be performed within this component</td><td><code>true</code></td><td><code>false</code></td><td><code>true</code></td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Data Map

A Data Map component allows users to create key/value pairs. Both the key and the value fields can get the values while filling out the form. New pairs can be added to the form by the 'Add Another' button and removed by the 'X' (Remove Row) button.

{% hint style="info" %}
The Key component cannot be changed and will always be a Text Field. The Value component can be changed from the default Text Field to any other component (e.g. Text Area, Number, Checkbox etc.).
{% endhint %}

{% tabs %}
{% tab title="Unique Settings" %}
**Label for Key Column:** A label text for a Key column. If left empty, the 'Key' label will be used by default.

**Disable Adding / Removing Rows:** Hides the 'Add Another' and the 'Remove Row' buttons.

**Show Key Column Before Value:** Makes the Key column show before the Value column. If unchecked, the Value column will show first.

**Add Another Text:** Sets the text of the 'Add Another' button.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/XWPrOXo>" %}
{% endtab %}

{% tab title="Guidance" %}

* Coming Soon...
  {% endtab %}

{% tab title="JSON" %}
**Component Schema**

```
{
  "label": "Data Map",
  "addAnother": "Add Key Pairing",
  "customClass": "pr-4 pl-4",
  "tableView": false,
  "key": "dataMap",
  "type": "datamap",
  "input": true,
  "valueComponent": {
    "type": "textfield",
    "key": "value",
    "label": "Value",
    "input": true,
    "hideLabel": true,
    "tableView": true
  }
}
```

**Data Map Data Structure:** dataMap being the Data Map key

```
{
 data: {
    dataMap {  
      key: "Kuhn - Kshlerin"
      key1: "Keebler, Brown and Lind"
      key2: "Franecki, Lehner and Prohaska"
    }
  }
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Data Grid

Data Grids allow users to add a grouping of components on a line item grid. Users can then add multiple rows of the component grouping inside the Data Grid. Additionally, any number of grids can be added within a form, which is especially useful when needing the ability to add or duplicate multiple fieldsets.

{% tabs %}
{% tab title="Unique Settings" %}
**Disable Adding / Removing Rows:** Hides the 'Add Another' and the 'Remove Row' buttons.

**Conditional Add Button:** Specify a condition when the 'Add Button' will be displayed.

**Allow Reorder:** When set, the user can reorder the Data Grid rows.

**Add Another Text:** Sets the text of the 'Add Another' button.

**Add Another Position:** Allows you to specify a position for the 'Add Another' button with respect to the Data Grid. The button can be at the top of the Data Grid, at the bottom, or in both places at one.

**Allow Reorder:** Allows reordering rows by dragging and dropping them.

**Equal Column Width:** Makes the column sizes be equal in width.

**Enable Row Groups:** Allows separating Data Grid rows into groups. You can add groups, specify their labels, select a number of rows that will be in certain groups and delete the groups. It's helpful if you want to set a specific number of rows in the Data Grid and separate them by groups (see an example below).

**Hide Group on Header Click:** Makes the group header clickable. When clicked, the entire group will collapse. When clicked again, it expands and shows the hidden rows.

**Initialize Empty:** Hides all visible rows when initialized.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/XWPrLOM>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use the **Minimum/Maximum** settings in the **Validation** tab to dictate the minimum or maximum number of rows that can be saved. When the Minimum number of rows has been met the Delete Row button will dynamically be removed. When the Maximum number of rows has been met, the Add Another Row button will dynamically be removed.
* Use different **Layout components** within the Edit Grid to create different field set formats
* Use the **Allow Reorder** setting to give users the ability to rearrange or rank the Data Grid rows.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Data Grid",
  "reorder": false,
  "addAnotherPosition": "bottom",
  "layoutFixed": false,
  "enableRowGroups": false,
  "initEmpty": false,
  "tableView": false,
  "defaultValue": [
    {}
  ],
  "key": "dataGrid",
  "type": "datagrid",
  "input": true,
  "components": []
}
```

#### Specific Properties

<table><thead><tr><th width="149">Property</th><th width="289">Description</th><th width="72">Value</th><th width="102">Required</th><th>Default</th></tr></thead><tbody><tr><td>components</td><td>An array of other components that represent a single row for the data grid.</td><td>[]</td><td><code>true</code></td><td>[]</td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Edit Grid

The Edit Grid replicates a table-like structure when it comes to the capture and display of form data. Users can add multiple components inside the Edit Grid. Additionally, any number of grids can be added within a form, which is especially useful when needing the ability to add or duplicate multiple fieldsets. There is also flexibility in how the Edit Grid data rows are saved and displayed to the end user.

{% tabs %}
{% tab title="Unique Settings" %}
**Open First Row When Empty:** When the form is initially loaded, an initial row is opened for the user to fill out. Please note that when this setting is checked, the row must be saved to submit the form, even if left empty.

**Disable Adding / Removing Rows:** Hides the 'Add Another' and the 'Remove Row' buttons. Use this setting

**Display Edit Grid as Table:** Uses the Table template for rendering the Data Grid.

**Conditional Add Button:** This gives a possibility to specify a condition when the 'Add Button' will be displayed.

**Header, Row, and Footer Templates:** Customize the grid to how you see fit using the Javascript [**Lodash**](https://lodash.com/docs/4.17.15#template) library. Within the Template section of the component settings, users can modify what type of components are displayed within the saved grid row along with the header/footer. By default, the templates will output all fields within the editgrid when a row is saved.

See the Field Examples tab for code and form examples.

**Add Another Text:** Sets the text of the 'Add Another' button.

**Display As Modal:** Shows up the form layout to add or edit a data entry in a modal view.

**Save Row Text:** Sets the text of the 'Save Row' button.

**Remove Row Text:** Sets the text of the 'Remove Row' button.
{% endtab %}

{% tab title="Field Examples" %}
**Edit Grid Examples**

{% embed url="<https://codepen.io/JeriahFormio/pen/JjarzQV>" %}

**Header / Row Template Example**

The following code examples showcase how to configure the Header and Row Templates using the Javascript [**Lodash**](https://lodash.com/docs/4.17.15#template) library. This allows the user to customize the way the Edit Grid displays data when a row is saved.

The use case - There are 7 different components inside my Edit Grid. I want the Edit Grid to showcase the most relevant fields to save horizontal space when the row is saved.

*Header Template* - Headers will change the column headers for the edit grid when the row is saved. In this example, I've created 3 columns with the headers: Employee ID, Name, Email

*Two available variables. "value" is the array of row data and "components" is the array of components in the grid.*

```
<div class="row"> 
  <div class="col-sm-2"> 
      Employee ID
    </div> 
   <div class="col-sm-2"> 
      Name
    </div> 
  <div class="col-sm-2"> 
      Email
    </div> 
</div>
```

*Row Template -* The Row template enables users to customize UI elements within a row like buttons and map the row's field data with a column in the header template. In this example, I'm using the *row* variable to map field data to an associated column in the header. The row buttons have also been customized to change the styling and text.

*Three available variables. "row" is an object of one row's data, "components" is the array of components in the grid, and "state" is the current row's state (can be "draft" or "saved"). To add click events, add the classes "editRow" and "removeRow" to element*s.

```
<div class="row"> 
    <div class="col-sm-2"> 
       {{ row.employeeId }}
    </div> 
    <div class="col-sm-2"> 
       {{ row.firstName}} {{row.lastName }}
    </div> 
 <div class="col-sm-2"> 
       {{ row.email }}
    </div> 
  <div class="col-sm-2"> 
    <div class="btn-group pull-right"> 
      <div class="btn btn-info editRow">Edit</div> 
      <div class="btn btn-danger removeRow">Delete</div> 
    </div> 
  </div> 
</div>
```

*Form Example*

{% embed url="<https://codepen.io/JeriahFormio/pen/WNmzeYM>" %}

*.*
{% endtab %}

{% tab title="Guidance" %}

* Use the **Display as Modal** setting when dealing with large field sets to save space on your form.
* Customize your **Header Templates** so only the most relevant field data is displayed when a row is saved. This will become necessary when dealing with large fieldsets.
* Use the **Minimum/Maximum** settings in the **Validation** tab to dictate the minimum or maximum number of rows that can be saved. When the Minimum number of rows has been met the Delete Row button will dynamically be removed. When the Maximum number of rows has been met, the Add Another Row button will dynamically be removed.
* Use different **Layout components** within the Edit Grid to create different field set formats
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Edit Grid",
  "tableView": false,
  "rowDrafts": false,
  "key": "editGrid",
  "type": "editgrid",
  "displayAsTable": false,
  "input": true,
  "components": []
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}


# Layout Components

Using and configuring Layout Components in the Form Builder

Layout components are used to change the general layout and position of fields on a form. Utilize HTML or a WYSIWYG editor to add logos, headers, or static contextual language to the form. You can find information for each of the Layout Components like unique settings, JSON code, and field examples below:

{% embed url="<https://youtu.be/3YMardxBb6U>" %}

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>HTML Element</strong></td><td>Write your own HTML to add headers, images, etc</td><td></td><td><a href="#html-element">#html-element</a></td></tr><tr><td><strong>Content</strong></td><td>Use a WYSIWYG editor to add and format text.</td><td></td><td><a href="#content">#content</a></td></tr><tr><td><strong>Columns</strong></td><td>Add columns to display fields side by side.</td><td></td><td><a href="#columns">#columns</a></td></tr><tr><td><strong>Field Set</strong></td><td>Create a Legend or Header for section in your form.</td><td></td><td><a href="#field-set">#field-set</a></td></tr><tr><td><strong>Panel</strong></td><td>Use a Panel to encapsulate groups of fields</td><td></td><td><a href="#panel">#panel</a></td></tr><tr><td><strong>Table</strong></td><td>Static table with rows and columns</td><td></td><td><a href="#table">#table</a></td></tr><tr><td><strong>Tabs</strong></td><td>Group fields inside vertical or horizontal Tabs.</td><td></td><td><a href="#tabs">#tabs</a></td></tr><tr><td><strong>Well</strong></td><td>Div class CSS wrapper</td><td></td><td><a href="#well">#well</a></td></tr></tbody></table>

### HTML Element

Add an HTML Element to a form to display a single HTML Element. This is useful if you wish to quickly insert and configure some HTML in your form. All unsafe HTML is stripped before rendering to prevent cross-site scripting exploits. This includes tags like `<script>`, `<embed>`, and `<style>`, and attributes like `onmouseover` or `onload`.

{% hint style="warning" %}
Ensure all HTML elements are properly closed as misconfigured HTML can cause issues with moving or editing other components on the form.
{% endhint %}

If writing HTML is not your preference, use the WYSIWYG editor with the [**Content component**](#content) as an alternative to writing HTML.

{% tabs %}
{% tab title="Unique Settings" %}
**HTML Tag:** The name of the HTML tag to display.

**CSS Class:** The CSS class to add to the HTML Element. You may specify multiple classes by separating them with single spaces.

**Attributes:** Attributes and their values to add to the HTML Element. This is commonly used to add `href` attributes to `<a>` tags, or `src` attributes to `<img>` tags.

**Content:** The text content of the HTML Element. While adding more child HTML tags here will properly display them, it is recommended you use the [**Content component**](https://help.form.io/form-building/components/layout-components#content) to easily write and preview more complex HTML.

**Refresh on Change:** Makes the HTML Element re-renders whenever any value in the form changes. It might be useful when you want the HTML Element to display dynamic data of the other components after they are filled in with values during the form filling. Simply enter`{{ data.{componentApiKey} }}` into the HTML Element and enable this setting.
{% endtab %}

{% tab title="Field Example" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/GRBbmJO>" %}
{% endtab %}

{% tab title="Guidance" %}

* Coming Soon...
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "HTML",
  "attrs": [
    {
      "attr": "",
      "value": ""
    }
  ],
  "refreshOnChange": false,
  "key": "html6",
  "type": "htmlelement",
  "input": false,
  "tableView": false
}
```

#### Specific Properties

<table><thead><tr><th>Property</th><th width="195">Description</th><th>Value</th><th width="133">Required</th></tr></thead><tbody><tr><td>tag</td><td>The HTML Tag to use for this element</td><td>Any HTML tag</td><td><code>true</code></td></tr><tr><td>attrs</td><td>An array of key-value pairs of attributes and their values to assign to this html element</td><td>Any HTML attribute</td><td><code>false</code></td></tr><tr><td>className</td><td>The class name to provide to the HTML Element</td><td>Any HTML class name</td><td><code>false</code></td></tr><tr><td>content</td><td>The HTML content to place within this element.</td><td>Any valid HTML</td><td><code>false</code></td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Content

A Content component may be added to a form to provide static content to the form, such as contextual language, headers, or media. For instance, if you need to provide instructions at the top of a form for display purposes only, use the Content component. The Content component value is **not** submitted back to the server. A WYSIWYG editor is provided within the component to format the content.

{% tabs %}
{% tab title="Unique Settings" %}
**Heading:** Choose a Heading 1-3 or Paragraph.

{% hint style="info" %}
Heading 1 = \<H2> html tag

Heading 2 = \<H3> html tag

Heading 3 = \<H4> html tag.

Content Component Headings start with H2 as H1 should be reserved for Page Titles, not content within a form context. For explicitly setting an H1 tag, the HTML Component can be used.
{% endhint %}

**Font Family:** Select your font style preference

**Font Size:** Change the font size from large to small

**Font Emphasis:** Add bold or italic emphasis to the content

**Link:** Add a hyperlink to the form

**Indent:** Increase or decrease the indent of the text

**Insert Media:** Add an image from your local machine and or add an online video via URL

**Align:** Align the text Left, Center, or Right
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/XWBLRRm>" %}
{% endtab %}

{% tab title="Guidance" %}
**Embed Video**

Use the Content component to embed a video within your form. [**Click Here**](/how/embedding-a-video) for more information

**Data Summary**

* Use the Content component as a 'Summary Section' by interpolating data from other fields on the form.
* Check the **Refresh On Change** setting to refresh the content anytime field data is changed on the form. This will ensure your summary section is constanstly updated with the latest date EG

```
{{ data.firstName }} 
```

![Interpolate data using the Content Component](/files/tLNLnVMNKAcd0NAcm3ac)
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Content",
  "refreshOnChange": false,
  "key": "content1",
  "type": "content",
  "input": false,
  "tableView": false
}
```

#### Specific Properties

| Property | Description                         | Value             | Required | Default |
| -------- | ----------------------------------- | ----------------- | -------- | ------- |
| html     | The HTML contents of this component | Any HTML `string` | `true`   |         |

#### Sanitize Configuration

In order to allow specific tags and attr in the content component, please see [**Sanitize Configuration**](https://github.com/formio/formio.js/wiki/Form-Sanitize-Config)

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Columns

This component can be used for grouping other components into configurable columns. Use Columns if you want to display multiple components inline. Columns can be utilized to save vertical space on a form and will collapse when the form is rendered on a mobile device.

{% tabs %}
{% tab title="Unique Settings" %}
**Column Properties:** Configured the number of available columns. Once set, components can be added to the columns by dragging and dropping a component into the column drop zone.

**Auto Adjust Columns:** If all the nested components inside one of the columns are hidden, all the other columns' positions will be adjusted.

{% hint style="info" %}
To evenly span your columns across the width of the form, the Column Property **Width** needs to equal 12 between all columns.
{% endhint %}
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/vYaqdoa>" %}
{% endtab %}

{% tab title="Guidance" %}

* Adding components into columns will ensure they respond in the correct order when viewing the form from a mobile device or screens with smaller widths.
* Ensure the Width total of your columns **equal 12** in order to span the columns across the full width of the form without spilling the fields under to the next line.

![Columns component settings](/files/1yIAYPdFfmntqyWbmqe7)
{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Columns",
  "columns": [
    {
      "components": [],
      "width": 6,
      "offset": 0,
      "push": 0,
      "pull": 0,
      "size": "md",
      "currentWidth": 6
    },
    {
      "components": [],
      "width": 6,
      "offset": 0,
      "push": 0,
      "pull": 0,
      "size": "md",
      "currentWidth": 6
    }
  ],
  "key": "columns1",
  "type": "columns",
  "input": false,
  "tableView": false
}
```

#### Specific Properties

<table><thead><tr><th width="120">Property</th><th width="240">Description</th><th width="269">Value</th><th>Required</th></tr></thead><tbody><tr><td>columns</td><td>The columns configuration and components.</td><td>This is an array of Column Configurations defined below.</td><td><code>true</code></td></tr></tbody></table>

#### Column Configuration

The columns definition is defined as an array of column configurations. Let's say you have 3 different columns, and your schema may look like the following.

```
{
  "type": "columns",
  "columns": [
    {
      ... COLUMN CONFIGURATION ...
    },
    {
      ... COLUMN CONFIGURATION ...
    },
    {
      ... COLUMN CONFIGURATION ...
    }
  ]
}
```

where each column configuration has the following schema.

<table><thead><tr><th width="164">Property</th><th width="271">Description</th><th width="131">Value</th><th width="108">Required</th><th>Default</th></tr></thead><tbody><tr><td>components</td><td>An array of other components within this column.</td><td>Array of Components</td><td><code>true</code></td><td>[]</td></tr><tr><td>width</td><td>How many Bootstrap grid units wide is this column</td><td>6</td><td><code>true</code></td><td>6</td></tr><tr><td>offset</td><td>The bootstrap column offset.</td><td>0</td><td><code>false</code></td><td>0</td></tr><tr><td>push</td><td>How many bootstrap grid units to push the column. (Bootstrap 3 only)</td><td>0</td><td><code>false</code></td><td>0</td></tr><tr><td>pull</td><td>How many bootstrap grid units to pull the column. (Bootstrap 3 only)</td><td>0</td><td><code>false</code></td><td>0</td></tr></tbody></table>

\
[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Field Set

Field Sets allows you to group multiple fields together in a form. It helps organize related fields visually and logically, making it easier to manage and present complex forms. Field Sets can be used to group fields under a common heading or section. The Field Set is for display only and will not be saved to the API.

{% tabs %}
{% tab title="Unique Settings" %}
**Legend:** The Legend is the title that is displayed for the Field Set
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/bGjXbMO>" %}
{% endtab %}

{% tab title="Guidance" %}

* The Field Set can act as the title of a section or area of your form. This can help with organizing groupings of components or sections of your form.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "key": "fieldSet1",
  "type": "fieldset",
  "label": "Field Set",
  "input": false,
  "tableView": false,
  "components": []
}
```

#### Specific Properties

<table><thead><tr><th width="145">Property</th><th width="266">Description</th><th width="132">Value</th><th width="97">Required</th><th>Default</th></tr></thead><tbody><tr><td>legend</td><td>The text to place within the legend of this fieldset.</td><td>Any <code>string</code></td><td><code>false</code></td><td></td></tr><tr><td>components</td><td>An array of components that are added within this fieldset.</td><td>Array of Components</td><td><code>true</code></td><td>[]</td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Panel

Panels are used to organize and group other form components into a collapsible or expandable section. Panels help structure forms by visually separating different sections or categories of information. They can include a title and be configured to open or close, which helps in managing and navigating complex forms by reducing clutter and improving the user experience. Custom CSS Styling currently defaults to [**Bootstrap Card - Header and Footer**](https://getbootstrap.com/docs/4.6/components/card/#header-and-footer).

{% tabs %}
{% tab title="Unique Settings" %}
**Theme:** The theming of the Panel. Select one of the options to have the class added to the wrapper div, changing the color of the panel header.

**Collapsible:** Turn the Panel into a collapsible Panel, allowing users to open and close the panel section.

**Initially Collapsed:** The Panel will be collapsed on form load. Applied only when the Collapsible setting is enabled.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/vYaoYOa>" %}
{% endtab %}

{% tab title="Guidance" %}

* Hide the label of the Panel to create an organized outline section for your component
* Use the **collapsible** setting with a large number of components, allowing users to hide the fields they don't want to see while they are filling one or another section of the form.
* Copy/Paste the Panel to recreate the panel along with all the components inside of it
  {% endtab %}

{% tab title="JSON" %}

```
{
  "collapsible": false,
  "key": "panel",
  "type": "panel",
  "label": "Panel",
  "input": false,
  "tableView": false,
  "components": []
}
```

#### Specific Properties

<table><thead><tr><th width="150">Property</th><th width="215">Description</th><th width="260">Value</th><th width="97">Required</th><th>Default</th></tr></thead><tbody><tr><td>title</td><td>The title of the panel</td><td>Any <code>string</code></td><td><code>false</code></td><td></td></tr><tr><td>theme</td><td>Any valid <a href="http://getbootstrap.com/components/#panels-alternatives">Bootstrap Panel Theme</a></td><td>One of <code>default</code>, <code>primary</code>, <code>success</code>, <code>info</code>, <code>warning</code>, <code>danger</code></td><td><code>false</code></td><td><code>default</code></td></tr><tr><td>components</td><td>An array of components that are within this panel.</td><td>Array of Components</td><td><code>true</code></td><td>[]</td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Table

The Table component allows you to arrange and present form fields in a table-like layout. This component is particularly useful for creating forms that require a clear and organized presentation of fields with sections that benefit from a tabular structure

{% tabs %}
{% tab title="Unique Settings" %}
**Number of Rows:** Number of rows that will display in the Table.

**Number of Columns:** Number of columns that will display in the Table.

**Clone Row Components:** Clones the components that are in a cell of one of the columns to all the other cells of that column. Use this if you want to add a lot of Table rows that will have the same content.

**Cell Alignment:** Horizontal alignment for cells of the Table. Can be Left, Center and Right.

**Striped:** Adds striped shading to the Table rows.

**Bordered:** Adds visible borders for the Table.

**Hover:** Highlights a row on a mouse hover.

**Condensed:** Condenses the size of the Table, making it takes less space.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/rNrXaBd>" %}
{% endtab %}

{% tab title="Guidance" %}

* Add HTML to the first row and column to create labels for your table. Add components and check the 'Hide Label' setting to create a clean-looking table.
* The Table component is not dynamically responsive and will not collapse when viewing the form on mobile devices or small screens.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Table",
  "cellAlignment": "left",
  "key": "table1",
  "type": "table",
  "numRows": 1,
  "numCols": 1,
  "input": false,
  "tableView": false,
  "rows": [
    [
      {
        "components": []
      }
    ]
  ]
}
```

#### Specific Properties

<table><thead><tr><th width="141">Property</th><th width="324">Description</th><th width="149">Value</th><th width="103">Required</th></tr></thead><tbody><tr><td>numRows</td><td>The number of rows for this table</td><td>integer</td><td><code>true</code></td></tr><tr><td>numCols</td><td>The number of columns for this table</td><td>integer</td><td><code>true</code></td></tr><tr><td>rows</td><td>A multi-dimensional array that provides the rows of the table. Within each row is another array that contains the columns of that row, and within that is the components that are contained within that cell of the table.</td><td>Multi-dimensional array</td><td><code>true</code></td></tr><tr><td>header</td><td>An array of strings that serve as the header for the columns of the table.</td><td>Array of strings for the table header.</td><td><code>false</code></td></tr><tr><td>striped</td><td>If the table should be striped</td><td>boolean</td><td><code>false</code></td></tr><tr><td>bordered</td><td>If the table should contain borders</td><td>boolean</td><td><code>false</code></td></tr><tr><td>hover</td><td>If the table should have a hover highlight over the rows.</td><td>boolean</td><td><code>false</code></td></tr><tr><td>condensed</td><td>If the table should be condensed</td><td>boolean</td><td><code>false</code></td></tr></tbody></table>

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Tabs

This component groups different sets of fields together into separate tabs. Similar to a Wizard flow, users can switch between tabs using a navigation bar with tab buttons, each of which opens a group of components. Only one tab at a time displays in a rendered form. The Tab CSS currently maps to [**Bootstrap Navs**](https://getbootstrap.com/docs/4.6/components/navs/).

{% tabs %}
{% tab title="Unique Settings" %}
**Tabs:** A data grid that allows adding, configuring, reordering, and removing tabs.

**Vertical Layout:** Makes the navigation bar display in a vertical orientation instead of the default horizontal layout.
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/poZMyYz>" %}
{% endtab %}

{% tab title="Guidance" %}

{% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Tabs",
  "components": [
    {
      "label": "Tab 1",
      "key": "tab1",
      "components": []
    }
  ],
  "key": "tabs",
  "type": "tabs",
  "input": false,
  "tableView": false
}
```

[**Click here for a full list of JSON Schema definitions**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)
{% endtab %}
{% endtabs %}

### Well

The Well component is a special type of form component designed to help with layout and visual separation within a form, making components inside the Well more user-friendly and visually appealing. Wells are wrapped in a div with a class mapped to [**Bootstrap Cards**](https://getbootstrap.com/docs/4.6/components/card/).

{% tabs %}
{% tab title="Unique Settings" %}
There are no Unique settings for the Well
{% endtab %}

{% tab title="Field Examples" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/PoBMzwX>" %}
{% endtab %}

{% tab title="Guidance" %}

* Use different classes to change the appearance of the Well.
  {% endtab %}

{% tab title="JSON" %}

```
{
  "label": "Well",
  "key": "well1",
  "type": "well",
  "input": false,
  "tableView": false,
  "components": []
}
```

{% endtab %}
{% endtabs %}


# Component Settings

Configuration options for the components

Forms are build by placing various components. These components have an array of settings that can be configured to change the interface, behavior, and functionality of the component. Some settings are available on all components, while others are unique to a particular component type. Below is a list of these settings organized by setting type.

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td></td><td><strong>Display</strong></td><td>Settings that visually change field elements</td><td><a href="#display-settings">#display-settings</a></td></tr><tr><td></td><td><strong>Data</strong></td><td>Settings related to how field data is set or interacted with from the Back-End</td><td><a href="/pages/RMPSmrLsLf42vdeQTxEI">/pages/RMPSmrLsLf42vdeQTxEI</a></td></tr><tr><td></td><td><strong>Validation</strong></td><td>Settings to configure Front-End and Back-End validations on the field</td><td><a href="#validation">#validation</a></td></tr><tr><td><strong>API</strong></td><td>Configures the API endpoint for the field as well as Custom Properties</td><td></td><td><a href="#api">#api</a></td></tr><tr><td><strong>Conditional &#x26; Logic</strong></td><td>Set up basic conditional workflows or advanced logic</td><td></td><td><a href="#conditions-and-logic">#conditions-and-logic</a></td></tr><tr><td><strong>Layout</strong></td><td>Configure HTML properties and PDF overlay positions</td><td></td><td><a href="#layout">#layout</a></td></tr></tbody></table>

{% hint style="info" %}
Click the **Hide Preview** button in the component settings to expand the options and conceal the field within the settings module.
{% endhint %}

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

## **Display Settings**

Settings that modify the front-end UI of a component. The Display setting tab will open by default when editing the component settings.

{% embed url="<https://www.loom.com/share/19295f201d564eeb8c9f02f4006514ad>" %}

### **Label**

The front-end name for the component. By default, the label will display at the top left of the field.

### Label Position

The label location of the component. The Lable Position will default to the Top option, but several other options can be selected:

* **Top** - The Label will display left aligned on the top of the component
* **Left (Left-aligned)** - The Label will display to the left of the component and aligned to the left of the component width span.
* **Left (Right-aligned)** - The Label will display to the left of the component and aligned to the right of the component width span.
* **Right (Left-aligned)** - The Label will display to the right of the component and aligned to the left of the component width span.
* **Right (Right-aligned)** - The Label will display to the right of the component and aligned to the left of the component width span.
* **Bottom** - The Label will display left-aligned below the component

### **Label Width & Margin**

When the Left or Right Label Position alignment options are selected, the label width and margin settings will become available. These options allow for padding to be added to the respective position of the component which will create space space between the label and the component. The width and margin values are based on the field's span percentage on the form.

{% hint style="info" %}
Use the label position when formatting your form in a grid-like fashion or to save vertical space on your form.
{% endhint %}

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

### Placeholder

A short descriptive text that describes the expected value that the user should enter in the field. The Placeholder will display when the field is empty and will not be submitted to the server when the form is submitted.

{% hint style="info" %}
Use the Placeholder as helper text for users filling out the field.
{% endhint %}

<figure><img src="/files/8rSgHFvsP8WQfvPRJhmQ" alt=""><figcaption></figcaption></figure>

### Description

Add a Description that will display below the field. This setting can be used as an alternative to the Placeholder or in addition if further details are needed for the field.

{% hint style="info" %}
Use HTML in the setting field to style the content of the Description
{% endhint %}

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

### Tooltip

Adding content to the Tooltip setting will add a new UI element to the field represented by a question icon next to the field label. The content inside the Tooltip setting will display when a user hovers over the UI element. Tooltips are a great way of providing detailed instructions or helper tips without taking up space on your form.

{% hint style="info" %}
Use HTML in the Tooltip setting field to style the content inside the Tooltip.
{% endhint %}

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

### Prefix

The Prefix setting adds text or characters before the input field. This can be used to categorize or label a field, like using $ for currency.

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

### Suffix

The Suffix setting adds text or characters after the input field. This can be used to categorize or label a field, like using % to represent a percentage.

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

### Custom CSS Class

Apply unique styling and formatting to your fields by adding Custom CSS Classes. Form.io utilizes [**Bootstrap**](https://getbootstrap.com/) as the default CSS framework for the renderer. Below are examples showcasing a few different Custom CSS Classes you may find useful and the class code.

#### **Field Background, Text Color** - <mark style="background-color:yellow;">`bg-info text-white`</mark>

<div align="left"><figure><img src="/files/ZuNqMimVjyAvoeEfHkXk" alt=""><figcaption></figcaption></figure></div>

#### <mark style="background-color:yellow;">Alerts, Padding</mark> - `alert-success p-3`

<div align="left"><figure><img src="/files/vGqlTckmiYcswcA1qtO1" alt=""><figcaption></figcaption></figure></div>

#### Reposition Fields - `float-right` , `float-left`

<figure><img src="/files/3x41il7Z4VR5HxdWE3sj" alt=""><figcaption></figcaption></figure>

Visit the [**Bootstrap Documentation**](https://getbootstrap.com/docs/5.3/getting-started/introduction/) site for a full list of customizable classes and tags you can apply to your fields and form.

### Tab Index

Configure the Tab Index attribute of this component to override the tab order of the form. Setting the tab order for all components on the form gives you control over the entire tab order of the form.

{% hint style="info" %}
See the [**MDN documentation**](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/tabindex) for more tab index information.
{% endhint %}

### Auto Complete

Enabled by default, input fields will automatically populate data from values previously entered by the user dictated by the cache of the user's browser. Input the *off* value inside the setting field to disable.

See the [**MDN documentation**](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete) autocomplete documentation for more information.

### Hidden

Hidden components do not display on the form but are still part of the form JSON and submission. This setting can be helpful when calculating data that should not be visible to the front-end user

### Hide Label

Hides the label of a field. Save vertical space on a form by hiding the field label and utilizing other display settings such as a Placeholder to identify the field.

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

### Hide Input

Masks the input of the field by replacing characters with circle characters often seen on password fields. Use this setting when handling sensitive data such as a Tax ID or Social Security Number.

{% hint style="warning" %}
Hide Input does not [**encrypt**](#encrypted) the data on the server. Do not use this setting for Passwords.
{% endhint %}

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

### Initial Focus

When the form is rendered, the component with Initial Focused checked will be the focused element on the form.

{% hint style="warning" %}
Only one component on the form should have the Initial Focus setting enabled. If more than one component on the form has the Initial Focus setting checked, only the last component in the JSON structure with the setting enabled will be focused on the form.
{% endhint %}

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

### Disabled

The Disabled setting will prevent users from focussing and inputting data into the field. Use Disabled fields in conjunction with Calculated Values to prevent a user from altering calculations or populated values.

<figure><img src="/files/6GriRCZrN8pTVvgByILr" alt=""><figcaption><p>Disabled fields will always display in gray</p></figcaption></figure>

### Table View

When the Table View setting is checked, the field and underlying data will display within the [**Submission Data Grid**](/form-building/submissions/accessing-submissions) of the form. "Data is always saved on the server, whether or not the setting is enabled.

{% hint style="info" %}
Adjust the Table View settings for each component in your form to streamline the submission grid in the Form's Data tab, ensuring that the most relevant data is displayed when reviewing submissions.
{% endhint %}

### Modal Edit

When this setting is enabled, the field is replaced with a button, that when clicked, launches a Modal Window to input and edit field data.

<figure><img src="/files/xMm5xyUjFCzKultdI8pJ" alt=""><figcaption><p>UI of the Modal Edit window when a field with this setting is selected</p></figcaption></figure>

{% hint style="info" %}
Enable this setting for a layout component to contain a multitude of fields inside a single modal window.
{% endhint %}

## Data Settings

Data settings are primarily utilized for configuring end-user input data, determining how it interacts with other field data within the form, and how it is stored on the server. Use Data Settings to perform tasks such as setting a default value or configuring data calculations.

{% embed url="<https://www.loom.com/share/7741d3be4e6543d194ce461767ffe1c9>" %}

### Multiple Value

The Multiple Value setting introduces an *Add Another* button below the field and allows the user to add or remove multiple rows of a component. Data is saved as an array within the submission.

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

### Default Value

Sets the default input value for the field which will display in the field when the form is rendered. If left unchanged, the default value data will be saved with the submission.

### Persistent

This setting will determine how the field data will be stored. Below are the following options for the Persistent setting. The default setting is set to Server:

**Server**: The Front-End **WILL** submit the data to the backend, and the backend **WILL** store the value

**Client-only**: The Front-End **WILL NOT** submit the data to the backend, and the backend **WILL NOT** store the value.

This can be beneficial when the server needs to intercept data for workflows such as logic or calculations, but there is no need or desire for the data to be stored.

**None**: The Front-End **WILL** submit the data to the backend, but the backend **WILL NOT** store the value.

Use this setting if client-side logic is needed on the form without the requirement of sending or saving the data to the server.

### Protected

This setting will prevent the field data from being queried from an API call. Check this setting if an extra layer of protection is needed for sensitive data.

### Database Index

Index the field within the database to increase server-side performance when querying submissions.

### Truncate Multiple Spaces

Removes any unnecessary spaces between words or characters within the field.

### Encrypted

Adds a server-side Encryption layer to the field. This is a two-way encryption not suitable for passwords. Form.io ensures the security of sensitive data through a multi-layered approach to encryption. At the foundational level, Form.io runs on MongoDB, and when using MongoDB Atlas, encryption at rest and in transit is provided by default, using advanced encryption standards to ensure that all data is protected at multiple layers.\
\
Building on this foundation, Form.io adds an additional layer of security through its encrypted fields functionality. This process leverages the robust aes-256-cbc algorithm, a symmetric encryption method known for its high level of security.\
To perform the encryption and decryption, Form.io utilizes the OpenSSL library via Node.js. Leveraging OpenSSL allows Form.io to securely encrypt data before storing it and decrypt it when necessary, ensuring that sensitive information remains protected throughout its lifecycle. The use of aes-256-cbc ensures that data is encrypted with a 256-bit key, providing a strong defense against unauthorized access.

{% hint style="info" %}
This setting is included in the [**Security Module**](/dev/the-security-module). Follow the link or contact <sales@form.io> for more information.
{% endhint %}

### Redraw On

Refresh the component when a specific change occurs. The Redraw setting dropdown will offer options to redraw the component when any change occurs on the form or when a specific field on the form changes selectable within the setting dropdown. Use this setting when interpolating data for calculations or logic when dynamic changes occur form.

{% hint style="info" %}
Use this setting when interpolating data on the form or setting up [**Dynamic Select Filtering**](https://app.gitbook.com/s/dE1To8ypyE1yhXEJ7QlD/cascading-select-dropdowns) workflows.
{% endhint %}

### Omit Value From Submission Data When Conditionally Hidden

{% hint style="info" %}
As of API Server version **9.4.0**, the Clear Value When Hidden setting has been renamed to **Omit Value From Submission Data When Conditionally Hidden**.

Please see the details below for changes to the setting's behavior.
{% endhint %}

This setting determines the behavior of a field's value when the field becomes conditionally hidden on the form. When components offer this setting, it is enabled by default. Disabling this setting on a component that offers it adds the flag *"clearOnHide" = false* to the component JSON.

When **enabled**, the field value is cleared when the component is hidden by conditions, and no value is submitted. If the component is unhidden by conditions, the value will remain blank. This is the expected behavior when conditionally showing or hiding components.

When **disabled**, even when the component is hidden by conditions, the field value will be submitted. If the component is unhidden by conditions, the previous value will still be displayed.

Fields hidden through the **Hidden** setting in the component's **Display** tab will retain their data in the submission, even if this property is enabled.

#### Nested Component behavior

When a nested component is hidden as a result of the parent being conditionally hidden, any child component with "Omit Value when Conditionally Hidden" will be excluded from the submission.

However, when a nested component is hidden as a result of the parent being conditionally hidden, the field value of that child component will not be cleared. If the parent component is unhidden by conditions, child components will display the previous value regardless of the "Omit Value when Conditionally Hidden" setting on the child component.

Child components will only have the field value cleared when then that component is specifically hidden by the conditions.

#### Example Scenarios:

1. **Single Component**: A text field hidden via a conditional logic rule with "Omit Data When Conditionally Hidden" enabled will exclude its value from the submission.
2. **Container/Group**: When an entire container is hidden by conditional logic and "Omit Data When Conditionally Hidden" is enabled at the container level, all fields within the container will be omitted from the submission, regardless of whether that setting is enabled for each field.
3. **Layout Components:** When any nested component is hidden as a result of the parent being conditionally hidden, the nest component field values **will not** be cleared. To override this behavior, manually add the "clearOnHide" property to the JSON of the component and sett that value to "true".
4. **Display Tab Hidden**: A field hidden using the **Hidden** setting found within the component the **Display** tab will retain its value in the submission, even when this property is enabled.

### Custom Default Value

Expand the Custom Default Value tab and write custom Javascript or JSON Logic to set the field's default value.

### Calculated Value

Expand the Custom Default Value tab and write custom Javascript or JSON logic to set up calculation logic on the field. This section allows you to write custom JavaScript snippets that will be evaluated to perform advanced calculations within your component.

The way that this works is that it will execute your snippet of JavaScript within an evaluation sandbox, which includes a number of variables (included below). The result of the calculation will then be set on a special variable called the "return" variable. In the case of Calculated Values, the name of this variable is called "value". It should be noted that the name of the "return" variable is different depending on if you execute a Calculated Value, Custom Conditional, as well as Logic Triggers and Actions. For example, let's suppose that you have a form with 2 number components A and B. You then drag and drop another component, called Sum onto the form. You can automatically set the value of the Sum component by providing the following in the Calculated Value section.

```
value = data.a + data.b;
```

In this example, we use the 'data' context variable to capture the values of Component A and B, and then assign the result of the calculation to the 'return' variable 'value.' During the evaluation, several variables are accessible for code execution. These variables make up the **Evaluation Context** which are detailed below:

#### Evaluation Context Variables

| Variable Name | Description                                                                                                                                                                                                                                          | Example                                                                                                                                                                         |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data          | The "root" data object for the subission.                                                                                                                                                                                                            | <p>{<br>"firstName": "Joe",</p><p>"lastName": "Smith",</p><p>"email": "<joe@example.com>",</p><p>"children": \[</p><p>{"name": "Joey"}</p><p>{"name": "Sally"}</p><p>]<br>}</p> |
| row           | The contextual "row" data for any component that may reside within an Array based component that has multiple rows. For example, a Textfield within a Data Grid component may have multiple rows, and each row would have a different "row" context. | {"name": "Joey"}                                                                                                                                                                |
| input         | FOR VALIDATION ONLY: The input value that was entered into the component to be validated                                                                                                                                                             | "hello"                                                                                                                                                                         |
| rowIndex      | The number of what row the component is currently within (if applicable)                                                                                                                                                                             | 2                                                                                                                                                                               |
| form          | The JSON of the full form definition                                                                                                                                                                                                                 | <p>{</p><p>"\_id": "...",<br>"title": "Customers",</p><p>"name": "customers",</p><p>"path": "customers",</p><p>"components": \[...]<br>}</p>                                    |
| submission    | The full JSON object for the submission of a form                                                                                                                                                                                                    | <p>{<br>\_id: "...",</p><p>created: "...",</p><p>modified: "...",</p><p>deleted: null,</p><p>data: {...},</p><p>metadata: {...}<br>}</p>                                        |
| component     | The JSON for the current component                                                                                                                                                                                                                   | <p>{<br>"type": "textfield",</p><p>"label": "First Name",</p><p>"key": "firstName",</p><p>"input": true<br>}</p>                                                                |
| options       | The global options passed to the renderer.                                                                                                                                                                                                           | <p>{</p><p>"pdf": true,<br>"readOnly": true<br>}</p>                                                                                                                            |
| t             | The translation function used to dynamically translate strings within your evaluation context.                                                                                                                                                       | `value = t('hello')`                                                                                                                                                            |
| iconClass     | A function that is able to dynamically swap out the iconset classes based on different templates that are loaded.                                                                                                                                    | iconClass('home')                                                                                                                                                               |
| \_            | A subset instance of Lodash for providing helper functions to your evaluations.                                                                                                                                                                      | `value = _.get(data, 'customer.firstName');`                                                                                                                                    |
| utils         | An instance of the Form Utils class. See <https://github.com/formio/core/blob/master/src/utils/formUtil.ts>                                                                                                                                          | var comp = utils.getComponent(form.components, 'firstName');                                                                                                                    |
| user          | The JSON of the currently authenticated user submission.                                                                                                                                                                                             | <p>{<br>\_id: "...",</p><p>data: {<br>email: "<joe@example.com>"<br>}<br>}</p>                                                                                                  |
| moment        | An instance of the "moment" library, or in later renderer versions, an instance of Day.js library to use for data manipulation                                                                                                                       | `value = moment('2022-01-33');`                                                                                                                                                 |
| token         | The current JWT token for the authenticated user.                                                                                                                                                                                                    | ---- A JWT TOKEN ---                                                                                                                                                            |
| config        | The current form configuration, or the Project Public configurations object                                                                                                                                                                          | `value = config.baseUrl;`                                                                                                                                                       |
| instance      | The current component instance. CAUTION: Only used approved instance methods when using "instance" within your evaluations. See below for the list of approved instance methods that can be used.                                                    | `value = instance.root.getComponent('firstName').getValue();`                                                                                                                   |

#### Return Evaluation Context variables

With every custom evaluation, there is a "return" variable that is used to set the response that is returned to the execution. Instead of adding your own "return" to the execution context, it is important instead, to simply set the value of the "return" variable so that your result can be returned. For example, if you wish to set the value of a Calculated Value you should do the following

**DO THIS!**

```javascript
value = data.a + data.b;
```

#### DO NOT DO THIS!

```
return data.a + data.b;
```

The name of the variable that you set depends on what evaluation you are performing. Here is a list of all the "return" variable names for when they are used.

| Evaluation           | Return Variable | Type                                                     | Example                                                       |
| -------------------- | --------------- | -------------------------------------------------------- | ------------------------------------------------------------- |
| Custom Default Value | value           | any                                                      | value = 'hello';                                              |
| Calculated Value     | value           | any                                                      | value = data.a + data.b;                                      |
| Custom Validation    | valid           | <p>true when valid<br>Error string when invalid</p>      | valid = (input === 'joe') ? true : 'Your name must be "Joe"'; |
| Custom Conditionals  | show            | <p>true when shown<br>false hidden</p>                   | show = !!data.showMe;                                         |
|                      |                 |                                                          |                                                               |
| Logic Custom Trigger | result          | <p>true when logic should execute<br>false otherwise</p> | result = data.age > 18;                                       |

#### Custom Evaluation Context Variables

When a form is embedded in your application, it is also possible to inject custom Evaluation Context variables into the renderer. This is done via the options parameter of our renderer like so.

```javascript
Formio.createForm(document.getElementById("formio"), "https://examples.form.io.example", {
  evalContext: {
    validatePhone: function(input) {
      return input.match(/^[2-9]\d{2}-\d{3}-\d{4}$/);
    }
  }
});
```

Now, when you create a form, you can use the following script within your custom Validation script.

```
valid = validatePhone(input) ? true : 'Phone number is invalid';
```

{% hint style="info" %}
If you define custom Evaluation Context variables using the embedded code in your application, these methods will NOT be executed on the Server during server-side execution of your scripts. If you wish for them to also be evaluated, then you should use the "evalContext" configuration within the Form Modul
{% endhint %}

#### "instance" usage and methods

Anytime you create a new script, there is the ability to use "instance" to provide more advanced functionality to your custom evaluation. This variable refers to the current instance of the component variable that triggered the evaluation. While this variable does provide an enormous amount of flexibility, it should also be used with extreme caution since upgrades of our platform may alter some of the methods that are used within the instance method. For this reason, we prefer that ONLY the following methods and variables are used in conjunction with instance to ensure the greatest stability and upgrade path.

| Property                        | Description                                                                                                                                                                                                                                                       | Example                                                                |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| instance.getValue()             | Returns the value of the current instance component.                                                                                                                                                                                                              | `value = instance.getValue();`                                         |
| instance.setValue(...)          | Sets the value of the component instance as well as forces the view to update as well.                                                                                                                                                                            | instance.setValue("hello");                                            |
| instance.updateValue(...)       | Much like "setValue", but instead of also updating the "view", this simply updates the model and leaves the view as-is. This is helpful to call on an event when the \<input> changes and you do not wish to create infinite loops.                               |                                                                        |
| instance.hasValue()             | Returns true if the component has a value, false if it does not.                                                                                                                                                                                                  | <p>if (instance.hasValue()) {<br>// Do something here...<br>}</p>      |
| instance.dataValue              | A "getter" to retieve the value of the component. This is similar to "getValue()" but does not have any side effects such as event emitting.                                                                                                                      | value = instance.dataValue;                                            |
| instance.dataValue = '....'     | A "setter" to set the value of a component. This is similar to "setValue()" but does not have any side effects such as event emitting.                                                                                                                            |                                                                        |
| instance.unset()                | Unsets the value for this component in the data model.                                                                                                                                                                                                            |                                                                        |
| instance.defaultValue           | Returns the value of the default value for this component.                                                                                                                                                                                                        |                                                                        |
| instance.getValueAt(num)        | For a component with "multiple" checked, this allows you to get the value of a component at any index in the multiple array.                                                                                                                                      |                                                                        |
| instance.setValueAt(index, val) | For a component with "multiple" checked, this allows you to set the value of a component at any index in the multiple array.                                                                                                                                      |                                                                        |
|                                 |                                                                                                                                                                                                                                                                   |                                                                        |
| instance.options                | The options passed to the renderer. Generally speaking, all options should remain reverse compatible and will not change from version to version.                                                                                                                 | <p>if (instance.options.pdf) {<br>// Only do something in pdf<br>}</p> |
| instance.component              | Returns the JSON of the current component.                                                                                                                                                                                                                        |                                                                        |
| instance.root                   | Returns the "root" instance of the webform. Typically, this will point to either Webform or Wizard depending on which type of form you are using this within.                                                                                                     |                                                                        |
| instance.refs                   | A map of all the DOM elements used within this component.                                                                                                                                                                                                         |                                                                        |
| instance.errors                 | An array of all validation errors this component has, including the ones that are not visible in the UI.                                                                                                                                                          |                                                                        |
| instance.on(...)                | Add a listener to this component to listen to specific events. CAUTION: using this method can cause serious memory leaks, it is preferred that if you use this, you should use it within the Custom Default Value evaluation since it is only ever executed once. |                                                                        |
| instance.emit(..)               | Emit a custom event on this component.                                                                                                                                                                                                                            |                                                                        |

### Calculate Value On Server

Check this setting if you would like to run your calculations on the server side. This is useful if you wish to override the values submitted on the back-end with the calculations performed on the server.

### Allow Manual Override of Calculated Value

Allows input data to override any calculations set on the field.

By default, the field value cannot be entered when a calculation is set on the field. Check this setting if you would like users to override the field calculation and set their own value.

### Server Override

Overrides current component settings when the form submission is processed on the server side. Add this setting if you want the form component to behave differently on the server side.

It can be useful when conditional components in your form have the 'Omit Value From Submission Data When Conditionally Hidden' option disabled, but you want the hidden data to be removed after the form is submitted. In this case the 'Server Override' setting should be configured as follows:

```
{
    "clearOnHide": true
}
```

## Validation

Settings found in the Validation Tab relate directly to the configurable Front-End and Back-End validations for the field. Validation covers settings such as required fields, unique data, min/max requirements, custom validations, and custom error messages.

{% embed url="<https://www.loom.com/share/b2c57d9e160e4e7aa12bc35b60b4b9a6>" %}

### Validate On

Determines when the field's front-end validation will occur based on the option selected:

**Change** - Validation will actively trigger any time there is a change in the field. This is the default option for every field.

**Blur** - Validation will only trigger when the field is no longer focused.

{% hint style="info" %}
Use the Blur option on fields that require a certain format to ensure validation is not triggered until the user has completed the data input. EG Email field
{% endhint %}

### **Required**

The Required setting is represented by a red asterisk next to the field label and forces the user to enter a value before the form is submitted or the user progresses to the next page of a Wizard form.

### **Unique**

Upon submission, a query is done on the back end to ensure the data entered into the field is unique.

{% hint style="info" %}
Apply this setting to an Email field on a registration form to ensure the address being entered has not been submitted to the database.
{% endhint %}

### Validate When Hidden

When this setting is enabled, the component is validated when it is hidden or conditionally hidden. The validation errors of the hidden components are shown in the form errors alert when submitting the form.

{% hint style="danger" %}
A hidden component holding an invalid value while **Validate When Hidden** is enabled will prevent the form user from submitting the form, without giving them direct access to the component to correct the invalid value. Ensure the form workflow accounts for this behavior.
{% endhint %}

### Minimum / Maximum Length

The Minimum or Maximum length requirement the field value must meet. This behavior changes depending on what component the setting is being applied to.

**String (EG Text Field, Text Area)** - Determined by the number of characters entered in the field

**Number - (EG Number, Currency)** - Determined by the numerical amount entered in the field

**Array (EG Data Grid, Edit Grid)** - Determined by the number of arrays or rows added to the grid

{% hint style="info" %}
Use the Minimum / Maximum length on Data Grids or Edit Grids to determine the number of rows a user can add or remove. The minimum value will result in the grid rendering that specific number of rows when the form is displayed.
{% endhint %}

### Regular Expression Pattern

Often referred to as Regex, this setting allows you to apply a pattern (or filter) that details a set of strings that must match the pattern. With a Regex Pattern set, the string must match the pattern before the form can be submitted.

### Error Label

Change the field name displayed within the validation message when validation is triggered.

{% hint style="info" %}
Use the Error Label when a field has a long label or name to shorten validation messages.
{% endhint %}

### Custom Error Message

Write a Custom Error Message that overrides the default front-end validation message displayed on the form when validation is triggered.

### Custom Validation

Expand the Custom Validation tab and write Javascript or JSON logic to set up your own validation rules for the field.

[**Click Here**](/form-building/logic-and-conditions#custom-validation) to read more about custom validation

### Secret Validation

This setting hides the javascript validation rules defined within Custom Validation from the JSON form definition and component settings for any user that does not carry the[ **Portal Base Project Administrative role**](/deploy/portal-base-project#admin-resource).

While the validation will function normally for all users, non-administrative users will see the following JSON in the form definition:\
\
`"customPrivate": true`.\
\
Additionally, the Custom Validation JavaScript code block will be blank for these users when viewing the field settings.

### Custom Errors

Set different custom error messages for multiple errors. For example, you could set up multiple error messages to communicate a required field and a min/max amount of characters (in contrast to “Custom Error Message”, which only allows you to set one error message for all errors).

## API

Component settings found in the API Tab contain Back-End settings such as the field's Property Name as well as custom properties that can be set such as HTML and Tags.

### **Property Name**

The back-end field identifier for the API endpoint. This field is auto-populated in camelCase based on the initial Label given to the field. Each field's Property Name must be unique on the form before the form can be saved.

{% hint style="info" %}
Use the Property Name when referencing the field via API or conditional logic.
{% endhint %}

### Field Tag

There are two pre-defined field tags:

* **viewer:hide -** When set, overrides any exiting logic and hides the component from the PDF display of a submission.
* **viewer:show -** When set, overrides any exiting logic and displays the component in the PDF display of a submission.

The Field Tag provides a flexible method for application layer interaction by letting form builders tag components with information that may be accessed and used inside and outside of the form. It may facilitate different workflows or be used to trigger within workflow logic in the form.

### Custom Properties

Apply Custom Properties to the field.

## Layout

Apply HTML Attributes / Properties and programmatically reposition PDF fields.

### HTML Attributes

Provide a map of HTML attributes for the component's input element.

{% hint style="info" %}
Attributes from other component settings or other attributes generated by form.io take precedence over the configured HTML Attributes.
{% endhint %}

### **PDF Overlay**

These settings allow the user to programmatically control the field position on PDF First Forms as well as custom styles. Use the margins to fine-tune overlay component locations on your PDF Forms.

**Style:** Custom styles applied to the component when the PDF is rendered.\
**Page:** The PDF page the component will display on\
**Left:** The Left Margin of the component location within the PDF form defined in pixels.\
**Top:** The Top Margin of the component location within the PDF form defined in pixels.\
**Width:** The width of the component in pixels.\
**Height:** The height of the component in pixels.

{% hint style="info" %}
Apply identical height measurements to all PDF overlay components to ensure a consistent height across all overlay components on the PDF form.
{% endhint %}

## Conditions and Logic

Create intelligent workflows using Form.io's Conditions and Logic system. Show or hide your fields, merge component JSON schema, conditionally set field settings, and more, all based on user interaction on the form.

[**Click Here**](/form-building/logic-and-conditions#custom-validation) to learn more.


# Enterprise Form Builder

The Enterprise Form Builder is a dedicated form-building and data management interface built specifically for non-developers. This application offers a team of non-developers the capability to easily manage forms and data without needing access to the Form.io project. This relieves the risk of unintentional modifications or changes to project settings that could potentially affect the stability of the application running on Form.io. Only forms designated by Project users are available within the interface. Take advantage of the white-labeling feature for the Form Manager application by adding custom logos, CSS, and branding within the project settings.

[**Learn more about the Enterprise Form Builder**](/dev/enterprise-form-builder-module)

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


# Logic and Conditions

Create intelligent workflows using Form.io's Conditions and Logic system. Show or hide fields, merge component JSON schema, conditionally set field settings, and more based on user interaction with the forms. Conditions and Logic provide more power and flexibility to the form builders. This gives end users a more personalized and structured experience when filling out a form.

## Conditional Show and Hide

Conditions are set on a per-field basis. To configure a show/hide condition, open the component field **settings** and click the **Conditional tab**.

There are two different methods to write conditions, **Simple** and **Advanced**.

Despite the name Simple Conditions offer fine-grained controls that can create intricate multivariable conditions based on other form fields and resources. They are powerful but lightweight and should be the primary mechanism of conditionally displayed components.

{% embed url="<https://youtu.be/kD6UrH_YnH8>" %}

**How Does It Work?**

The Simple Conditional tab allows the user to show or hide fields based on user input, or based on the value of other fields on the form. These conditions are readily configurable in the component settings UI. The following settings are available to configure conditionals:

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

* **Show or Hide this field -** Select whether to **Show** the field or **Hide** the field when the conditions are met.
* **When -** Multiple conditions can be configured on a per-component basis. Select whether to show or hide the field when **One** or **All** conditions are met.
* **Conditions -** The **Condition** section is the criteria that will execute the workflow. Multiple conditions can be added to create complex workflows using an easy-to-use UI. method. Click the **+Add Condition** button to configure a new conditional.
  * **When -** Select what component within the form will execute the condition.
  * **Is -** Comparison Operator that evaluates and compares the value of the selected field before the condition is executed. The type of field set for the condition will dictate the available operators the user can select.

<details>

<summary>Comparison Operator Definitions (Expand)</summary>

**Is Equal To:** This field’s value must match the condition value.

**Is Not Equal To:** This field’s value must not match the condition value.

**Is Empty:** This field value is empty ( `null`, `undefined`, or an empty string (`""`)).

**Is Not Empty:** This field contains some value (not `null`, `undefined`, or an empty string(`""`)).

**Less Than:** This field’s value is less than the condition value.

* For **string fields**, it compares the number of characters (string length).
* For **number fields**, it compares the actual numeric value.

**Greater Than:** This field’s value is greater than the condition value.

* For **string fields**, it compares the number of characters (string length).
* For **number fields**, it compares the actual numeric value.

**Less Than Or Equal To:** The field’s value is less than or equal to the condition value.

**Greater Than Or Equal To:** The field’s value is greater than or equal to the condition value.

</details>

* **Value -** The string value the field needs to contain for the condition to activate. If the conditional field uses static values—such as those from a Radio or Select component—the predefined options will be displayed in the Value drop-down as the trigger value for the condition

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

The combination of all of these settings will determine when the condition is executed on the form. Multiple conditions can be applied to the same component to create advanced conditional workflows

{% hint style="warning" %}
When a condition has been added, **all** parts of the condition must be entered in order to save the component.
{% endhint %}

#### Use Cases

The powerful logic engine is used to decide whether to hide or show a component based on the form user's interaction or response on one or many components. This creates a dynamic form experience that can help form users enter data in a more fluid way.

In the example below, an email field should only display when a Checkbox is ticked and a certain value of a Radio component is selected. Two conditions, one for the checkbox and one for the Radio, are used to trigger the workflow when both conditions are met:

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

{% tabs %}
{% tab title="Example Form" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/eYrxOPw>" %}
{% endtab %}

{% tab title="Watch Video" %}
{% embed url="<https://drive.google.com/file/d/1ocLXXheBiFyuWPL1WzIJZbUlV652FaCr/view?usp=sharing>" %}
{% endtab %}

{% tab title="Copy Form" %}
Import the **Simple Conditional** form into your project using the following Embed URL:

**<https://kiajjsgmjcrqziu.form.io/simpleconditional>**
{% endtab %}

{% tab title="Guidance" %}
Use the **Simple** method when setting up a condition that is dependent on **one field**.

* Save form space by showing relevant fields based on user input
* Create a cohesive and personalized experience for your form users
* Design a 'Choose your own adventure' form workflow with branching fields
* Save time setting conditionals on multiple fields by including those fields inside a Layout component and applying the condition to the Layout component.
* [**Additional Documentation and Examples**](http://formio.github.io/formio.js/app/examples/conditions.html)
  {% endtab %}
  {% endtabs %}

### **Advanced Conditions**

Conditions can also be created using [JSON Logic](https://jsonlogic.com/) or JavaScript custom code to conditionally show or hide fields on the form, when the required functionality can't be achieved through the Simple Condition tools.

{% hint style="danger" %}
JavaScript conditions require secure evaluation in order to execute. This introduces an amount of overhead that can degrade form performance when used frequently or significantly within a form.

Additionally, security policies in the application or form user environment may further affect JS execution and performance.

Form.io suggests, as a best practice, to always attempt to use Simple Conditions
{% endhint %}

This can be useful if the conditional relies on a sub-function within the JavaScript code comparing different values. This provides the form builder with the freedom and flexibility to write complex conditions as they see fit.

{% embed url="<https://youtu.be/caeFjLVccV4>" %}

Before writing JavaScript it's important to note the available **variables**:

<table data-header-hidden><thead><tr><th width="368.5">form</th><th>The complete form JSON object</th></tr></thead><tbody><tr><td><strong>form</strong></td><td>The complete form JSON object</td></tr><tr><td><strong>submission</strong></td><td>The complete submission object</td></tr><tr><td><strong>data</strong></td><td>The complete submission data object</td></tr><tr><td><strong>row</strong></td><td>Contextual "row" data, used within DataGrid, EditGrid, and Container components</td></tr><tr><td><strong>component</strong></td><td>The current component JSON</td></tr><tr><td><strong>instance</strong></td><td>The current component instance</td></tr><tr><td><strong>value</strong></td><td>The current value of the component</td></tr><tr><td><strong>moment</strong></td><td>The moment.js library for date manipulation</td></tr><tr><td><strong>_</strong></td><td>An instance of <a href="https://lodash.com/docs/"><strong>Lodash</strong></a></td></tr><tr><td><strong>utils</strong></td><td>An instance of the <a href="/spaces/DuAwTOTr6NFMpkfgwq9x/pages/GF7FYb4iKxiTUMzYK8Bc"><strong>FormioUtils</strong></a> object</td></tr><tr><td><strong>util</strong></td><td>An alias for "utils"</td></tr></tbody></table>

Use the **show** function to start the line of JavaScript when conditionally showing or hiding.\
In the following **example**, this conditional field will display when the Currency field has a value less than $45,000. There's also a sub-function that will show the field when the previous condition is met and the Radio field has the value 'single' **or** 'widowed':

{% code overflow="wrap" %}

```
show = (data.income < 45000) & (data.maritalStatus == 'single' || data.maritalStatus == 'widowed');
```

{% endcode %}

The **data** variable is being used here to reference the input data from the 'Enter your annual income' and the value selection from the 'Select your marital status' field. When referencing fields, ensure you are using the [**Property Name**](/form-building/component-settings#property-name) of the trigger component inside your JavaScript. The Property Name can be found within the **API Tab** of the component settings.

<figure><img src="/files/S5zWp1qGAnjj1I6YXjK1" alt=""><figcaption><p>Use the Property Name when referencing a component inside your code</p></figcaption></figure>

When referencing a value selection, ensure it uses the **Value** and not the Label inside the JavaScript code. Component values can be found in the **Data Tab** of the component settings. This applies to the Radio, Select, and Select Box components.

<figure><img src="/files/7yJRS1gLfBBC55GiebE8" alt=""><figcaption><p>Use Values when referencing selection data inside your code</p></figcaption></figure>

#### **JSON Logic**

Use JSON Logic as an alternative to JavaScript when writing Advanced Conditions. The same concepts detailed in the Advanced Conditions section still apply. Replace the Javascript variables and operators with JSON Logic.

[**Follow this link for JSON Logic examples and documentation**](https://jsonlogic.com/)

{% tabs %}
{% tab title="Form Example" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/abGXqOX>" %}
{% endtab %}

{% tab title="Watch Video" %}
{% embed url="<https://drive.google.com/file/d/1fVjoXolQtJyz8qEgzo5COuFXmcAiDIw-/view?usp=sharing>" %}
{% endtab %}

{% tab title="Copy Form" %}
Import the **Advanced Conditional** form into your project using the following Embed URL:

[**https://kiajjsgmjcrqziu.form.io/advancedconditions**](https://kiajjsgmjcrqziu.form.io/advancedconditions)
{% endtab %}

{% tab title="Guidance" %}
Use the **Advanced** method when setting up a condition based on data input from **multiple fields** on the form.

* Ensure you are using the fields **Property Name** and **Value** of the trigger field when setting up your condition.
* Save form space by showing relevant fields based on user input
* Create a cohesive and personalized experience for your form users
* Design a 'Choose your own adventure' form workflow with branching fields
* Save time setting conditionals on multiple fields by including those fields inside a Layout component and applying the condition to the Layout component.
* [**Additional Documentation and Examples**](http://formio.github.io/formio.js/app/examples/conditions.html)
* [**JavaScript Documentation**](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
* [**JSON Logic Documentation**](https://jsonlogic.com/)
  {% endtab %}
  {% endtabs %}

## Logic

**What is the Logic feature?**

The Logic feature provides a more robust rules engine to conditionally control and manipulate field settings, JSON schema, data values, and custom events. The Logic feature is applied on a per-field basis with the ability to add multiple Logic instances to the field if needed.

**Why should I use Logic?**

Use the Logic feature when complex conditions are required and you need to conditionally control things like field settings, schema, or data values. The Logic system also allows the user to set multiple triggers and different branches of conditional actions on a single field. Whether you're setting up simple one-to-one conditions or creating complex workflows, the Logic feature is available to meet those needs.

**How do I use Logic?**

To access the Logic feature, open the components settings of the conditional field and click the Logic tab. Click the **+Add Logic** button to create a new logic instance. Give the Logic instance a name that is easily identifiable in the future.

{% embed url="<https://youtu.be/D987nxWkxOg>" %}

### Triggers

Set the **Trigger Type** to determine how the condition is structured and triggered. Configuring the Trigger will depend on what type of Trigger Type is selected. The Trigger Types are listed below:

**Simple:** The Simple Trigger type utilizes the same UI and configuration methods found in the Conditional tab. Refer to the [**Simple Conditional Documentation**](#simple-conditions-8.0.x) for more information.

**Javascript**: Write your own custom conditionals using JavaScript code. The JavaScript Trigger type utilizes the same UI and configuration methods used for Advanced Conditionals. Refer to the [**Advanced Conditions Documentation**](#advanced-conditions) for more information.

**JSON Logic:** Use JSON Logic as an alternative to JavaScript when writing Logic Conditions. Refer to the [**JSON Logic Documentation**](#json-logic) for more information.

**Event:** Use the Event option when creating your own custom events on your form.

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

### Actions

Now that our Trigger is set, add an action that will execute when the condition is triggered. Click the **+Add Action** button, give the Action a name, and select an action **Type**. This will dictate what type of action will execute when the condition is triggered.

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

There are four **Action Types** you can choose from:

**Property:** Conditionally change field settings such as Required, Label, Disabled, and more! Depending on the selected Component Property, configure the **Set State** to **True** or **False** (EX setting a required flag) or input the conditional property **Text** (EX changing the Label property).

**Value:** Change or populate data values in the conditional field using Javascript. The following variables are available to use in your Javascript code:

"row", "data", "component", and "result"

**Merge Component Schema:** Not all field settings and configurations are offered with the Property action type. Directly update the field Schema Definition to configure additional settings using Logic conditions, dynamically change labels or value selections, and populate interpolated data from other fields.

**Custom Action** Execute a custom event workflow. Typically coincides with other fields such as the Hidden Field, Data Source, and Button components.

{% hint style="info" %}
Add multiple actions to a single Logic instance or add multiple Logic instances to your conditional field to facilitate more complex workflows
{% endhint %}

{% tabs %}
{% tab title="Example Form" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/YzLBKmQ>" %}
{% endtab %}

{% tab title="Copy Form" %}
Import the **Logic** form into your project using the following Embed URL:

[**https://kiajjsgmjcrqziu.form.io/logic**](https://kiajjsgmjcrqziu.form.io/logic)
{% endtab %}

{% tab title="Guidance" %}

{% endtab %}
{% endtabs %}

## Custom Validation

**What are Custom Validations?**

Write custom Javascript or JSON code to satisfy complex validation rules and workflows on a per-field basis.

**Why should I use Custom Validations?**

While Form.io offers pre-defined validation rules such as required fields, min/max input values, and unique data submissions, at times, custom validation rules may be needed to satisfy rules and requirements unique to an application. This ensures that the data a user enters in a field meets the standards specified by the form designer before the user can submit the form.

These custom rules provide a unique form experience for end users, allowing form designers to create customized validations specific to their application and form needs.

**How do I use Custom Validations?**

Open the components settings of the field you want to apply the validation rule to and click the **Validation tab**. Open the Custom Validation panel and write Javascript or open the JSON Logic Validation panel to write custom JSON.

{% embed url="<https://youtu.be/pACGuMbpG58>" %}

Review the [**Advanced Conditions**](#advanced-conditions) documentation to reference the available Javascript variables.

**Example**

In the following example, I need to validate that the data of the 'Confirm Email' field matches the 'Primary Email' field data using Javascript.

Use the **valid** function to start the line of code. Add the **input** variable to reference the **data** from the Primary Email field. Use the **`? true:`** variable to input the custom message when the validation is triggered.

```javascript
valid = (input === data.email) ? true: 'Emails must match';
```

{% hint style="info" %}
When referencing another field, use the Property Name of the referenced field in your code. The Property Name is found in the API tab of the component settings.
{% endhint %}

{% tabs %}
{% tab title="Example Form" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/WNybRqw>" %}
{% endtab %}

{% tab title="Copy Form" %}
Import the **Custom Validation** form into your project using the following Embed URL:

**<https://kiajjsgmjcrqziu.form.io/customvalidation>**
{% endtab %}

{% tab title="Guidance" %}
-Use Custom Validation to validate matching fields like email or passwords

-Setup complex password requirements

-Use Validate On options in the Validation settings to determine when the Validation will be triggered
{% endtab %}
{% endtabs %}

## Calculated Values

**What are Calculated Values?**

Calculated Values allow form designers to write custom Javascript or JSON code to facilitate data calculation between different fields on a form.

**Why should I use Calculated Values?**

A common requirement for modern web forms is business-based calculations between fields on your form. Whether you're creating order forms, quote request forms, payroll forms, and the like, Form.io equips you to satisfy complex calculation requirements for modern web forms necessary in today's industries.

**How do I use Calculated Values?**

To apply field calculations, open the component settings and click the **Data** tab. Scroll down the settings window, click the **Calculated Value** panel, and add your Javascript code to the code block

Review the [**Advanced Conditions**](#advanced-conditions) documentation to reference the available Javascript variables and functions.

{% embed url="<https://youtu.be/V7QCCXVFgBU>" %}

**Example**

In the following example, we are going to set up Javascript calculation between two fields and populate that data into a 'Total' field

Use the **value** function to start the line of code. Next, add the **data** variable and reference the **Property Name** of the fields you wish to calculate.

```
value = data.fieldA + data.fieldB
```

{% hint style="info" %}
When referencing a field, use the Property Name of the referenced field in your code. The Property Name is found in the API tab of the component settings.
{% endhint %}

{% tabs %}
{% tab title="Example Form" %}
{% embed url="<https://codepen.io/JeriahFormio/pen/jOKPEja>" %}
{% endtab %}

{% tab title="Copy Form" %}
Import the **Calculated Value** form into your project using the following Embed URL:

**<https://kiajjsgmjcrqziu.form.io/customvalidation>**
{% endtab %}

{% tab title="Guidance" %}
-Setup a workflow to interpolate data from one field to another

-Merge Strings into a single field

-Setup mathematical calculations between numeric fields
{% endtab %}
{% endtabs %}


# Form Revisions

Form Versioning can extend the capabilities of any project cycle by giving users the ability to evolve current forms while preserving the integrity of previous iterations. Form Versioning allows for detailed deployment tracking, allowing teams to see who has updated a form, when a change was made, and any notes associated with the update. Additionally, Form Versioning can be used to revert to previous incarnations while safeguarding all submission data.

Form Revisions are part of the [Security Module](/dev/the-security-module). Please contact <sales@form.io> for more information on adding this module to your current License Subscription.

{% hint style="info" %}
Form Revisions are available for all Trial projects on portal.form.io
{% endhint %}

{% embed url="<https://www.loom.com/share/edda96d7f1404705870585729c3ffbcf>" %}

### Enable Form Versioning <a href="#enable-form-versioning" id="enable-form-versioning"></a>

To get started, create or enter an existing project. For the purpose of this walk-through, an HTML element will be anchored to the top of each form to keep track of the current iteration.

![](/files/XINdcvtwzrd4eAMpcYst)

To enable Form Versioning, expand the `Advanced Settings` tab by clicking on it.

![](/files/fedZPXfIMI5L0ar23Glf)

In the Form Revisions section, expand the select dropdown menu and select either `Enable` option.

![](/files/1s38Cnt1ska9W81NCceH)

Form Revisions can be configured in two different ways:

* **Enabled** – Use the current form version when viewing a submission
  * Will display all form submission data in the most recent form revision.
* **Enabled** – Use the original form version when viewing a submission
  * Will display form submission data in the form revision that it was captured in.

This functionality extends to wherever users choose to view their submission data. This includes viewing their data from within the **\<form.io>** platform or externally like inside the user's application.

Afterward, click either `Create Form` if creating a new form or `Publish` when interacting with an existing form. Once saved, **Form Versioning** is now enabled and the `Revisions` tab is now available for user interaction.

![](/files/gWZNN8SNx73x9h99MLFu)

Once inside the revisions interface, users can see the full scope of their current development cycle. Important information such as who made the revision, when the revision was made, the revision number, and any notes made are all available. Additionally, several actions are now available.

* Use
  * Will enter the traditional form `Use` tab in that form revision.
* Data
  * Will display form submission data that was captured in that form revision.
* Restore
  * Will make a clone of the current revision, iterating the Vid to the most recent revision.

These items will be covered in depth further down.

### Creating Form Revisions <a href="#creating-form-revisions" id="creating-form-revisions"></a>

With **Form Versioning** enabled, users can begin iterating through different form revisions. Note that this revision has a new field added. Additionally, this guide has iterated the tracking HTML field manually to illustrate a change in form version, this is not an automatic process.

![](/files/mlNMzBPeIIcdO3i7xktH)

At the bottom of each form, users can enter a revision note that will appear alongside other important information in the `Revisions` tab once published.

![](/files/pa9t2VyhhInbOiwbTHU9)

Once complete, click the `Publish Form` action will create a new revision and will be visible on the revisions page.

![](/files/Q9kvUDtvCk8HJqB2EFg4)

Note that the system has automatically iterated the Vid number now that multiple revisions exist.

### Using Form Revisions <a href="#using-form-revisions" id="using-form-revisions"></a>

By default, the `Use` tab will display the most recent form revision (the one with the highest Vid).

![](/files/rvbjrw5ponABoECuuTJY)

However, users can interact with the `Use` action from within the `Revisions` tab to use specific form revisions.

![](/files/uGPRGmc4XzFs1gLRXdSH)

When using Vid #1, the original form is displayed, notice how **(C) Version Field** is no longer present.

![](/files/DdbYO9sjNdpucATeu4Wb)

When using Vid #2, notice **(C) Version Field** is present again as well as the change to the tracking field.

![](/files/rKwkvke4Re7chsM22oJt)

### Viewing Revision Data <a href="#viewing-revision-data" id="viewing-revision-data"></a>

A 3rd revision has been added where **(B) Version Field** has been removed. Additionally, the following submissions have been made to each of the form versions:

* Version 1: 2 submissions made
  * (A) { Apple1, Apple2 }
  * (B) { Banana1, Banana2 }
* Version 2: 3 submissions made
  * (A) { Apricot1, Apricot2, Apricot3 }
  * (B) { Blueberry1, Blueberry2, Blueberry3 }
  * (C) { Cherry1, Cherry2, Cherry3 }
* Version 3: 2 submissions made
  * (A) { Avocado1, Avocado2 }
  * (C) { Carrot1, Carrot2 }

A simple inspection of the `Data` action for Vid #1 will reveal the two submissions listed in the table above.

![](/files/2wyHA6TbWETDzfIM0Xnp)

N

Notice that only submissions made using Vid #1 are displayed. Ergo Apricot and Avocado entries are not present.

![](/files/eOWQG90xwObB2TXNaD3h)

To view all submissions, click the `Data` tab at the top and all 7 entries will display.\
Notice, that **(B) Version Field** entries are not displayed.

![](/files/xMTWCtMlUOAEnwf9Jrfn)

Not to worry, as illustrated above, the data is still there. Recall that the most recent form revision removed **(B) Version Field** and as a result, the data table only displays key-value pairs that already exist within the active form.

### Restoring Form Revisions <a href="#restoring-form-revisions" id="restoring-form-revisions"></a>

Since **(B) Version Field** data is hidden due to the current form revision not having that field, the restore action can be evoked to recover the former layout. From the `Revision` tab, selecting `Restore` will being the restoration process.

![](/files/LywjlafSwSPLV82Pbef9)

Afterward, users are redirected to the form editor where additional revisions can be made, a revision note can be made, and other components added. Notice, that **(B) Version Field** has been restored and a note has been made.

![](/files/2s66TRaYAUMsLDOkxjUv)

Upon publishing the form, a return visit to the `Revisions` tab will reveal a new revision, Vid 4. Additionally, the note made during the restoration process is also visible.

![](/files/9Dl4FlNGXg7xGek8EVPG)

It is important to note that restoring a form does not overwrite or alter the original revision. Instead, a new revision is made which is why there are now 4 revisions. Continuing, a visit to `Data` tab will reveal that **(B) Version Field** and its respective data have returned.

![](https://help.form.io/assets/img/userguide/versioning-restore-4.png)

### Creating Form Drafts <a href="#creating-form-drafts" id="creating-form-drafts"></a>

**Form Versioning** also supports a draft feature where changes can be made without publishing a new version. Continuing with the example, **(D) Version Field** has been added and saved as a draft.

![](/files/7QXrbUyj4D29xCcVNwXG)

An inspection of the revisions tab will reveal that a draft now exists.

![](/files/sFhwyTWs76nG0kYnMHvn)

Drafting is primarily used to test form construction without overwriting the active form revision. As a result, once a draft is published, it will disappear from the revisions page. Lastly, there can only ever be one active draft at a time.


# Form View Pro

Form.io is a Developer-Centric tool that is leveraged by developers to build out their own custom applications.

The Form View Pro application is a minimal sample application that is packaged with the formio-enterprise Docker Container delivered software.

{% hint style="danger" %}
The Form View Pro application is intended to be a lightweight, boilerplate application and is **NOT** a replacement for an end-user facing application.
{% endhint %}

This application is included with the Form.io project and can be accessed by Launching a form, to enable testing forms outside of the Developer Portal Application.

[**Learn more about the Form View Pro application here**](/form-building/form-view-pro/formview)

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


# Using Form View Pro

Describes the Form.io FormView application

The Form View Pro application is included with the Form.io project and can be accessed by Launching a form, to enable testing forms outside of the Developer Portal Application.

A form hosted through this application will be found at the URL [**https://pro.formview.io**](https://pro.formview.io) after it is launched, as seen below:

![](/files/SWDsDFh4l7DTnF5iGla4)

For more information on the Launch Form feature, check out the documentation on [**Launching a Form**](/launch).

Many features and workflows are **not** suitable candidates to be served through the Form View Pro application.

## Form View Pro Configurations

Configurations are provided to the Form View Pro application using Query parameters. For example, Bootswatch Themes can be selected for displaying forms with the styling of these themes.

```
https://pro.formview.io/#/examples/example?theme=materia
```

This switches the theme that is used to render the Form View application like so:

![](/files/lkJ9btqRv6hiUfatVt0M)

#### Public Configurations

Form View Pro can also be configured using a project's Public Configurations. This provides an interface where each project can provide public configurations that are used to control the behavior of their applications, but it can also be used as the configuration mechanism for the Form View Pro application. To change the Form View Pro configurations:

1. Open the project on the Form.io Devleoper Portal as a user with sufficient privileges.
2. Click the **Settings** option on the left-hand menu.
3. Navigate to the **Public Configurations** of the project as follows.

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

| Query Parameter / Setting | Description                                                                                                                                                                                                                                                              |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| theme                     | Changes the theme of the rendered form. The names that can be used coincide with the Bootswatch themes found @ [**https://bootswatch.com/**](https://bootswatch.com/). Clicking on the "Themes" link on this page will show all the different themes that are available. |
| css                       | Add a custom CSS file url to apply to the form. Must be a hosted CSS file.                                                                                                                                                                                               |
| js                        | Add a custom JS file url to apply to the form. Must be a hosted JS file.                                                                                                                                                                                                 |
| reset                     | Resets all "cache" from previous form sessions. Useful to send as a URL to a user that will ensure they are not affected by cache.                                                                                                                                       |
| src                       | A custom Form URL. You would use this instead of using the `#/{PROJECT_NAME}/{FORM_NAME}` in the url.                                                                                                                                                                    |
| return                    | A URL to navigate to once the form has been submitted.                                                                                                                                                                                                                   |
| header                    | To hide or show the header. `header=0` will hide the header.                                                                                                                                                                                                             |
| iframe                    | To place this viewer in "iframe" mode where it removes all padding and headers.                                                                                                                                                                                          |
| host                      | Force the API Host for the form that is being rendered. Useful if you wish to render a form from a different deployment.                                                                                                                                                 |
| protocol                  | Force the URL protocol for the host. (https or http)                                                                                                                                                                                                                     |
| token                     | Force an Auth Token (JWT) to be used for this form submission. Used when sending an email that automatically logs into the application.                                                                                                                                  |
| sso                       | Provides an SSO authentication into the FormView application. Can be "saml" or "okta"                                                                                                                                                                                    |
| saml                      | Same as "sso" but uses "saml" by default.                                                                                                                                                                                                                                |
| branding                  | With any Enterprise Subscription, remove the Form.io logo from FormviewPro by setting to "false"                                                                                                                                                                         |

## Launching a Form

Click the **Launch** tab in the form header to configure settings that will affect the form in the FormView Pro application as well as launching the form within the applicaiton.

### **Share Settings**

Configure these settings to modify how the form is displayed and behaves within the FormView Pro application.

#### Theme

Choose a Bootstrap theme to display the form in the FormView Pro application

**Show Header**

Check this setting to display the Form Name, Login Button, and any Logos added using Public Configurations within the Formview Pro application header.

**Enable Thank You Page Editor**

Check this setting to enable a WYSIWYG editor located at the bottom of the page. The content within this editor will display for the end-user after submitting the form within the FormView Pro application.

<figure><img src="/files/WhixmpgLNA6WfIPwYTh8" alt="" width="563"><figcaption></figcaption></figure>

#### Go To Form

Click this button to launch the Form within the FormView Pro applicaiton

#### Make Public / Make Private

Click this button to enable/disable Anonymous submissions which allows unauthenticated users to submit the form within the application.

This setting will add or remove the **Anonymous Role** to the **Create Own Permission** within the Access settings of the form.

[**Read More About These Permissions Here**](/admin/roles-and-permissions#submission-data-permissions)

## Authentication

Generally, SSO or an existing authentication scheme is integrated with a custom application as well as the Form.io context, for seamless use of Form.io within a custom application.\
\
The Form View Pro application can however leverage a Form.io Resource for authenticating into this application for testing purposes only. Review the [**Form Manager Authentication**](/admin/form-manager#authentication) documentation to get an idea how to authenticate within the Form View Pro application.

## Submission View

To view the Submissions of a form, the above authentication must be set up. Then, once logged into the app, by clicking on the Submissions link at the top of the screen, Submissions can be viewed.

![](/files/OMHlIB50C7pPlNsiJSmn)

This page provides a list of all the submissions of this form visible to the logged-in user. If authenticated as an Administrator, all submissions should be visible; if logged in as a User, only submissions created by that user will be seen. This could change based on the Access settings configured on the form.

![](/files/5BINzmZ8Sbogad3oec2s)

#### Submission View Columns

The fields shown in the columns of the Submission View can be controlled by configuring each field within the form and checking or unchecking the **Table View** flag.

![](/files/7bEvPJHxy5pqxklr2tZu)

Unchecking this field will then remove the field from the submission view which will enable this view to be customized based on which fields you would like to show when viewing submissions.

## Deployed Environments

Every deployed environment receives has a unique Form View Pro application provisioned to it, used to launch forms within that environment **for testing purposes only**. The URL of the Form View Pro application within any deployed environment can be found at the following URL:

```
https://yourserver.com/yourproject/manage/view
```

Where `yourserver.com` and `yourproject` are the names of the domain and project respectively. For Developer Portal deployments, it is also possible to get to the Deployed Form View Pro application using `formio` as the project name.


# Using Nested Forms

Additional details about the Nested Form premium component.

Use **Nested Forms** to save time by constructing forms that will be re-utilized through the course of a project and application. The Nested Forms component can integrate Child Forms into all different kinds of parent forms within an application, all while collecting and housing submission data into one primary source.

Nested forms may themselves contain nested forms. The maximum depth of nested forms is 5. The platform will not process submissions from a form greater than 5 levels away from the parent form.

{% hint style="warning" %}
Nested Forms with the "Save as Reference" option selected behave significantly differently. Refer to the appropriate [section of this document](#the-save-as-reference-option) for guidance and best practices.
{% endhint %}

## Example

In the following example, consider a form and its set of fields, which have been standardized to be reused multiple times throughout a project, in various other Forms. Instead of recreating the same fields and settings, create a single form called *Contact Info*. This will become the Child Form:

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

Next, add this form to one of the existing forms inside the project. The screenshot below shows a Parent Form:

<figure><img src="/files/8t4jEMPVEUPZRVp0WsOY" alt=""><figcaption></figcaption></figure>

Instead of adding individual fields, drag and drop the Nested Form component onto the Parent Form and configure it to pull in the Contact Info form:

<figure><img src="/files/jqO3NmL9izvGimA44H5n" alt=""><figcaption><p>Nest Form configuration.</p></figcaption></figure>

Note the "Save as reference" option. This is described in greater detail later in this document. The configured Nested Form component will appear in the Form Builder as follows:

<figure><img src="/files/Yr5c6e7VLjdhcUL4HfWu" alt=""><figcaption><p>The Parent Form with the Nested Form configuration.</p></figcaption></figure>

When the form is rendered the fields from the Parent Form are visible, in addition to the fields included in the Child Form. All settings and configurations for the Child Form fields are retained:

<figure><img src="/files/VrOiGcEOUs5f70fFiRrs" alt=""><figcaption><p>Parent Form displaying the nested Child Form components, highlighted in blue.</p></figcaption></figure>

## Form JSON

Even though the form renderer will display the Child Form components as usual within the Parent Form, the Parent Form JSON will not directly contain the components of the Child Form. Instead, it will contain a *pointer to* the Child Form, in the form of the Child Form's reference ID. The reference ID can be found in the Form JSON of the Child Form, typically as the first line. The form JSON of a Nested Form component will look similar to the following snippet.

```json
"components": [
    {
      "label": Nested Form display label,
      "tableView": true,
      "form": Form_ID_of_Child_Form,
      "useOriginalRevision": false,
      "reference": false, //refer to "Save as reference" section for guidance
      "key": nested_form_component_name,
      "type": "form",
      "input": true
    },
```

## Submission Data

When a Parent Form is submitted, the submission data will merge the child and parent data together. On the Developer Portal **Data** tab, a submission against the Parent Form will display data contained within the Child Form in a column labeled with the name of the Nested Form component, and recorded as "\[Complex Data]".

<figure><img src="/files/r8POvr4OOb83cbPL66jL" alt=""><figcaption><p>The Data Tab of the Parent Form recording a submission.</p></figcaption></figure>

The JSON of a submission against a Parent Form will contain the data submitted against all components of the Child Form. It will look similar to the following:

```json
data:
   parent_component1: submitted_value
   parent_component2: submitted_value
   <nested_form_component_name>: 
      data:
         child_componentA: submitted_value
         child_componentB: submitted_value
```

## Editing a Child Form

Saving changes to a Child Form will cause the changes to that form to be reflected in all Parent Forms that have included it as a Nested Form when those Parent Forms rendered.

If a component is added to the Child Form, any submissions recorded before the addition of that field will not contain any references to it. If a component is deleted, any submissions recorded before the deletion will still contain that data. Ensure your data handling and business processes account for this when modifying a Child Form.

If the optional Form.io Security Module is purchased and deployed, the desired revision of the Child Form can be specified when configuring the Nested Form component on the Parent Form.

<figure><img src="/files/lKhxqebVBqs84r9wLtLJ" alt="" width="375"><figcaption><p>Select a specific revision of the Child Form.</p></figcaption></figure>

Additionally, the option "Use Original Revision while Submissions Viewing" will ensure the same revision of the form that was used to generate a submission is used whenever that submission is viewed, regardless of what the revision is currently nested in the Parent Form.

<figure><img src="/files/3wAyixboCu9reXjnNlyi" alt="" width="375"><figcaption></figcaption></figure>

## The "Save as reference" Option

The "**Save as reference"** option in the **Form** tab of the Nested Form Component changes the behavior of the component and submission data in several ways.

<figure><img src="/files/3tQEpJoPyqltrieikQA5" alt="" width="375"><figcaption><p>The "Save as reference" option in the Nested Form component.</p></figcaption></figure>

### Form JSON with "Save as reference" enabled

The Form JSON of a Nested Form component changes slightly when "Save as referenced" is enabled:

<table data-card-size="large" data-column-title-hidden data-view="cards" data-full-width="true"><thead><tr><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td><p>{</p><p>"label": "Contact Info",</p><p>"tableView": true,</p><p>"form": "676ac85d54e952a35e7f307b",</p><p>"useOriginalRevision": false,</p><p>"key": "contactInfo",</p><p>"type": "form",</p><p>"input": true</p><p>},</p></td><td></td><td><em>Form JSON with "Save as reference" enabled</em>.</td><td></td></tr><tr><td><p>{</p><p>"label": "Contact Info",</p><p>"tableView": true,</p><p>"form": "676ac85d54e952a35e7f307b",</p><p>"useOriginalRevision": false,</p><p><mark style="color:yellow;"><strong>"reference": false,</strong></mark></p><p>"key": "contactInfo",</p><p>"type": "form",</p><p>"input": true</p><p>},</p></td><td></td><td><em>Form JSON without "Save as reference" enabled.</em></td><td></td></tr></tbody></table>

### Submission Data with "Save as reference" enabled

When "Save as reference" is **enabled**, the form submission will be recorded against the Parent Form as well as the Child Form. On the Developer Portal **Data** tab, the Parent Form data will be recorded as seen earlier in this document:

<figure><img src="/files/mCP271uhJgXuZ7h5VRWh" alt=""><figcaption><p>The Data Tab of the Parent Form recording a submission will be the same when the Child Form is Saved As Reference.</p></figcaption></figure>

Since the Child Form will record Parent Submissions as its own submission, and it may be included in other Forms across the project, the Data tab will record submissions from all Parent Forms that enable "Save as reference." In this example below, the highlighted submission came from the example Parent Form, and matches the submission seen above:

<figure><img src="/files/ijV6Ko6AMpjtk3sL1hna" alt=""><figcaption><p>The Data Tab of a Child Form with submissions recorded from multiple Parent Forms.</p></figcaption></figure>

When "Save as reference" is enabled, the submission JSON is slightly different:

<table data-card-size="large" data-view="cards" data-full-width="true"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><p>data:</p><p>trip: "roundTrip"</p><p>vehicleType: "bus"</p><p>numberOfPassengers: 18</p><p><mark style="color:yellow;"><strong>submit: true</strong></mark></p><p>contactInfo:</p><p>data:</p><p>firstName: "Richard"</p><p>lastName: "Reference"</p><p>email: "referee@form.io"</p><p>phoneNumber: "(312) 106-1309"</p></td><td></td><td><em>Submission JSON with "Save as reference" enabled</em>.</td></tr><tr><td><p>data:</p><p>trip: "oneWay"</p><p>vehicleType: "van"</p><p>numberOfPassengers: 5</p><p>contactInfo:</p><p>data:</p><p>firstName: "Dereck"</p><p>lastName: "Direct"</p><p>email: "noreference@form.io"</p><p>phoneNumber: "(512) 212-7474"</p><p>metadata: {}</p><p><mark style="color:yellow;"><strong>submit: true</strong></mark></p></td><td></td><td><em>Submission JSON without "Save as reference" enabled</em>.</td></tr></tbody></table>

### Editing Submission Data with "Save as reference" enabled

Remember that when "Save as reference" is enabled, a form submission is recorded against both the Parent Form and Child Form.

When a submission recorded with "Save as reference" is edited, the update is applied to both the Parent Form and Child Form. Editing a submission of the Parent Form will change the corresponding values in the submission of the Child Form synchronously. Editing a Child Form submission that was created by a Parent Form submission will change the corresponding values in the Parent Form submission.\
If a Parent Form submission is edited without changing any fields recorded in the Child Form submission, the "Updated" time of the matching Child Form submission will reflect this edit, even though no fields were changed.

This synchronization across submissions has significant effects and should be considered when designing forms and workflows.

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

### Editing Child Forms With "Save as reference" enabled

The "Save as reference" setting does not affect the way changes to Child Forms are rendered in Parent Forms. Remember that saving changes to a Child Form will cause the changes to that form to be reflected in all Parent Forms that have included it as a Nested Form.

If the Child Form is changed, such as the addition of a new component, future submissions will record values for that field, though submissions recorded prior to the addition will not have any value on the Data tab and will not refer to the field in the submission JSON:

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

## **Nested Forms For Remotely Deployed Projects**

If a project is remotely deployed with subdirectories, set up the application to perform an API call like the following:

```
 Formio.setProjectUrl(<project_URL>). 
```

This will help Form.io understand where to fetch nested resources from and will set up base URLs properly.


# Resources

Use Resources as data objects within your forms or application

### **What are Resources?**

Resources are a very important piece of the \<form.io> platform and are used to define data objects within a project. These Resources can be referenced within other forms or within your application to create complex nested resource relationships. Once a resource has been created, it can then be used as a RESTful database within your application where new entities can be created, read, deleted, and queried like you would any other database collection.

### **Why should I use Resources?**

Resource objects not only define the API and back-end data model but also the front-end UI, meaning they can also be utilized as a normal form. These Resource data models can be used within other forms making it simple to create a data collection and reference that data in your form. Use a Resource to reference User credentials within your application for authentication, collection of reference data to utilize in other forms or an application, dynamic select filtering, etc.

### **How do I use Resources?**

Resources are created the same way as forms by using the Drag and Drop form builder. Once a Resource Form is in place, define the Data Object by making submissions against the Resource.

<figure><img src="/files/N3cfKhtGHMCZWd9OFq2f" alt=""><figcaption><p>Resource created for Regional Manager database and reference point</p></figcaption></figure>

New entities can be created, read, deleted, and queried like you would any other database collection.

<figure><img src="/files/YHDaSSjwRWwZa6bLE35m" alt=""><figcaption><p>Create your data object by making submissions against the Resource</p></figcaption></figure>

After data has been submitted, the Resource will now be established and ready to be utilized as a RESTful database within your application or other forms.

<figure><img src="/files/INX3N1J3IfMcGBAIo9Bn" alt=""><figcaption><p>Using a Select Resource field is one way you can reference the Resource data object</p></figcaption></figure>

​[**Click here for an in-depth explanation of how Resources and Forms work**](/form.io-concepts)​​

### **Best Practices & FAQ**

* Create a Resource anytime a Data Object reference is needed for your applications or forms.
* Use the Data Import feature to easily establish a Resource data object
* Setup [**Cascading Select Dropdowns**](https://app.gitbook.com/s/dE1To8ypyE1yhXEJ7QlD/cascading-select-dropdowns) using Resources and Select Resource fields
* Reference User Resource data for [**User Authentication**](/admin/roles-and-permissions)**​**
* Use [**Select Resource fields**](/form-building/basic-components#select) to reference Resource field data on your forms
* Use the Data Source component to pull in large amounts of data from your Resource to fields on your Form.
* Resources can also be used to create and house pre-defined fields called [**Existing Resource Fields**](/form-building/resources-readme/existing-resource-fields)


# Existing Resource Fields

Using pre-defined fields in a Resource as components of a form

**What are Existing Resource Fields?** Existing Resource Fields are components within your Resources that can be re-utilized in other Forms or Resources using the Form Builder. Existing Resource Fields carry over component settings, like validation and input masks, that have already been pre-configured within your Resource.

**Why should I use Existing Resource Fields?** Existing Resources Fields are very beneficial in the fact they save time and allow consistency when using the same type of fields and settings. This concept allows users to create a dedicated resource for pre-configured fields. This is an efficient way of configuring fields that you know will be needed for other Forms or Resources.

**How do I use Existing Resource Fields?** Start by creating a Resource and adding certain field types. Configure the field settings as needed.

<figure><img src="/files/321Kk2X92H0kO7UKLYST" alt=""><figcaption><p>Create your pre-defined fields within a Resource</p></figcaption></figure>

Create a new Form or Resource. The Existing Resource Fields are found at the bottom of the Form Builder component list. Clicking the Existing Resource Field tab will display each Resource within your project. Clicking a Resource within this list will display the components found in that specific Resource. Simply drag and drop a field just like any other component to add to a form.

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

Any field added to a Form from the Existing Resource Field list will carry over all pre-configured settings. Below is an example of a Date/Time field configured for Date of Birth input with required validation and a tooltip to provide users information about the field. Because this field was configured within a Resource, the Date of Birth field can be added to any Form or Resource and retain all settings and configuration.

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

**Best Practices & FAQ**

* Create a specific Resource to house all of your pre-defined fields
* Existing Resource Fields can be further modified once they have been added to a Form.
* Create your own 'Groupings' of components by adding a Layout component to your Resource and adding your fields within the layout type. Dragging the Layout component will also include the fields saved within that layout. This can be beneficial when a grouping of fields will be reutilized within other forms. For example, creating a User Information panel with fields like Name, Email, Phone Number, etc.
* Existing Resource Fields **do not** *link* Resources and Forms together
* If a field within a Resource is updated or changed, that field will not dynamically update if it has previously been added to other Forms. Users will need to remove and add the field again to their Form or Resource to update the settings. Alternatively, you can manually update the field settings instead of deleting and adding the field back to the form from the Existing Resource Field list.
* The field's property name can only be changed from the Resource side. Ensure the Property Name is correct within the Resource before using the field.


# Using Resources as a Select Component Data Source

Additional information and design considerations when using a Resource as the Data Source for a Select Component.

Using a Resource as the Data Source for the selectable choices in a Select Component is a common workflow. This permits, for example, user-defined data to be incorporated into the Select Component's choices. As the Resource is polled when the Form is rendered, the choices available in the Select Component can vary significantly between uses, which can significantly alter the data included in a Form submission.

When choosing to use a Resource as the Data Source for a Select Component, it is important to consider how Resource data is managed and what impact this has on Submission data. One important consideration to this end is the **"Save as reference"** option available in the Select Component settings.

<figure><img src="/files/P5yKOaGciesDP6q02RTo" alt="" width="563"><figcaption><p>Choices availalable when Data Source is set to Resource.</p></figcaption></figure>

To examine the impact of this option, consider the following Transport Request Form with a Driver Select Component that is populated from a Driver Resource.

<figure><img src="/files/NOL1SwYk6IrNybqU491r" alt=""><figcaption><p>The Select Component data source is a Resource.</p></figcaption></figure>

<figure><img src="/files/7oF0GAE7VAtOirv3xWUi" alt=""><figcaption><p>The Driver resource used to populate the Select Component</p></figcaption></figure>

The value chosen within the Select Component is stored in the Submission Data as expected:

<figure><img src="/files/gMYNySfsdtS3Q18rzqqk" alt=""><figcaption><p>Submission Data with the Driver recorded.</p></figcaption></figure>

As with the [**Nested Form component**](/form-building/premium-components#nested-form), enabling the "Save as reference" function affects the way edited Submissions are recorded. When "Save as reference" is enabled, editing the resource following a submission will update the data in the recorded submission:

<figure><img src="/files/WRRB9mJKOyuBqLajjLrT" alt="" width="563"><figcaption><p>Editing a submission of the Driver Resource.</p></figcaption></figure>

<figure><img src="/files/CexDdrodm7tnpS9hbzrg" alt="" width="563"><figcaption><p>The Resource Data tab, reflecting the update.</p></figcaption></figure>

After editing the resource, any submissions recorded while the Select component was configured to "Save as reference" will reflect the update:

<figure><img src="/files/mFqEbKXSP9kALxWMaprd" alt=""><figcaption><p>The updated field is reflected in the Form Submission Data.</p></figcaption></figure>

{% hint style="info" %}
Note that even though the data recorded was updated, and the Resource's "Updated" field reflects the time, the original submission's "Updated" time does **not** change.
{% endhint %}

In contrast, the Submission of the form where "Save as reference" is **not** configured will retain the same data:

<figure><img src="/files/gMYNySfsdtS3Q18rzqqk" alt=""><figcaption><p>Data remains unchanged when "Save as reference" is <strong>not</strong> configured.</p></figcaption></figure>

### Data Stability and Race Conditions

It is important to consider that when using a Resource as the Data Source for a Select Component, multiple actors within the project may be editing the Resource at any time.\
If the Resource is configured with "Save as reference," it is possible for Submission data to change if the resource is edited any time after the Submission is recorded. When this effect is intended, it is important to factor this into the application as a whole, as cached versions of the Submission data may not reflect such updates. Be careful to account for all downstream considerations that may arise when Submission data is configured to change synchronously with the Resource field.

Additionally, it is important to remember that a Form may directly or indirectly affect a Resource used as a Data Source within itself. This can create unanticipated and unpredictable behavior. Ensure that all workflows within the application that may alter a Resource that is used as a Data Source are sufficiently decoupled from processes that rely on that Resource as an input.

The following diagrams illustrate the relationship between the Select Component, the Resource, and the Submission, and the way the "Save as reference" option affects this relationship.

In the first example, the Resource supplies selectable fields for the Select Component's drop down. When one of these is selected and the form is submitted, the Submission will record the selected value as it was stored in the Resource at the time of the submission.

<figure><img src="/files/GbMSilc8k09PS0THnLzc" alt=""><figcaption><p>The Resource serves as the Data Source for the Select Component. The selected field is submitted.</p></figcaption></figure>

In the next illustration, the Resource is modified, but "Save as reference" is not selected. As a result, only submissions made after the change will reflect the alteration.

<figure><img src="/files/NqRMEDMZRIDYt9X3BPd1" alt=""><figcaption><p>Without "Save as reference" configured, only new Submissions will store an edited value.</p></figcaption></figure>

In the final illustration, "Save as reference" is selected. As a result, the previously recorded submission will reflect the change to the Resource, even if no new submission is made.

<figure><img src="/files/rrBkH4grpoAtklgBJTcW" alt=""><figcaption><p>The previously recorded Submission may be changed when "Save as Reference" is enabled.</p></figcaption></figure>


# Actions

Configuring actions that fire on submission of a form

Actions are ways of extending Form.io to perform tasks when there is form submission activity. These actions can be triggered when certain things occur like a form submission, submission update or deletion, and so on. There can be multiple actions on any given form providing the ability to initiate different business workflows. For example, you can authenticate a user account against your User Resource, send an email with data details, or fire off a webhook to send the data to an external system.

## Adding an Action <a href="#adding-an-action" id="adding-an-action"></a>

To add an action, go to the Actions tab of a form. Select the type of action from the dropdown then click the **Add Action** button. You can add multiple actions to run on each form submission.

Click the **Edit** icon to open the action's configuration settings. Click the red **Trash Can** icon to delete the action from the Form or Resource.

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

## Common Settings

All actions perform different functions, however, many of the actions share some common settings that can be configured by the user.

**Title:** The name or label of the action. Modify the Title to provide more of a description of the action's specific purpose or function. The Title will display on the Action overview page.

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

**Handler:** The handler determines whether the action will be sent **Before** or **After** the MongoDB query mechanism (that is, before or after your submission is saved to the database). If you select both, it will run twice, once before your submission is saved and once after.

**Method:** The Method determines when to run this action on a form. Select which system events will trigger this action:

* **Create** - Action will fire when a new submission is created
* **Read** - Action will fire when a submission is Read (or viewed)
* **Update** - Action will fire when a submission is updated
* **Delete** - Action will fire when a submission is deleted
* **Index** - Action will fire when indexing (or searching) a submission within the Database

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

**Action Conditionals:** Use the Simple conditional drop down workflow or write your own JavaScript to execute the action only when certain conditions have been met on the Form or Resource. The Conditional system is the same system used to facilitate field conditions.

[**Read more about Conditions here**](/form-building/logic-and-conditions)

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

## Action Logs

{% hint style="info" %}
Action Logs are part of the [Security Module](/dev/the-security-module) only. Please contact <sales@form.io> for more information on adding the Security Module to your current License Subscription.
{% endhint %}

Action Logs will display a log of triggered actions and relevant contextual information about those executions. This feature must first be enabled on a per form basis before the Action Logs are documented. Click the 3 dotted settings button, Action Logs, then select Enabled from the setting drop down.

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

Once enabled, any executed action will be documented within the Logs. Each log provides the user with relevant information that can be searched and filtered like the Date/Time, Action type, or the Action status, which can be particularly helpful when finding a failed action.

* **Date/Time** - Indicates when the log was recorded
* **Submission** - Provides the Submission ID the Action is associated with.
* **Action** - Details the type of action
* **Handler** - Determines if the action was executed before or after the submission
* **Method** - What Submission CRUD operation the action was executed

{% hint style="warning" %}
**Action Logs will be automatically deleted after 30 days.**
{% endhint %}

Clicking a line item in the Log will give you detailed information about the Action's execution process. This can be very helpful when tracking down any issues that might be occurring with the Action.

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

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Email</strong></td><td>Fire off an email when submission activity occurs on a form</td><td></td><td><a href="/pages/XbITDdnMK7QLLfonZu9B">/pages/XbITDdnMK7QLLfonZu9B</a></td></tr><tr><td><strong>Login</strong></td><td>Verifies user credentials against a Resource when authenticating into an application</td><td></td><td><a href="/pages/QxkaqAJOobmELKZWMZYy">/pages/QxkaqAJOobmELKZWMZYy</a></td></tr><tr><td><strong>Role Assignment</strong></td><td>Add, modify, or remove a role from a user when certain submission activity occurs</td><td></td><td><a href="/pages/nDnoFYDse8epLK2IbhwA">/pages/nDnoFYDse8epLK2IbhwA</a></td></tr><tr><td><strong>Save Submission</strong></td><td>Map the form field data to other Resources within a project.</td><td></td><td><a href="/pages/d9mXavAa0gBahUAxfZrF">/pages/d9mXavAa0gBahUAxfZrF</a></td></tr><tr><td><strong>Webhook</strong></td><td>Use a webhook to integrate your form submission into other applications or databases</td><td></td><td><a href="/pages/ajr9rtvznLEhAEvBIUcN">/pages/ajr9rtvznLEhAEvBIUcN</a></td></tr><tr><td><strong>OAuth</strong></td><td>Authenticate users using a OAuth provider</td><td></td><td><a href="/pages/rlN6aX6UgcuY51KnAV9k">/pages/rlN6aX6UgcuY51KnAV9k</a></td></tr><tr><td><strong>LDAP Login</strong></td><td>Authenticate users against a LDAP service provider.</td><td></td><td><a href="/pages/dZiyt2AeifgUoOM8YCgi">/pages/dZiyt2AeifgUoOM8YCgi</a></td></tr><tr><td><strong>Google Sheets</strong></td><td>Map form data to a Google Sheet spreadsheet</td><td></td><td><a href="/pages/wdCASQcMC5XlHE6vE17k">/pages/wdCASQcMC5XlHE6vE17k</a></td></tr><tr><td><strong>SQL Connector</strong></td><td>Deprecated</td><td></td><td><a href="/pages/Wm0hCpWMJtFpMDPMmPXU">/pages/Wm0hCpWMJtFpMDPMmPXU</a></td></tr><tr><td><strong>Group Assignment</strong></td><td>Facilitates group based permissions assigned to users within the group</td><td></td><td><a href="/pages/ASWf6F6uPBN7psqh0SxL">/pages/ASWf6F6uPBN7psqh0SxL</a></td></tr><tr><td>2<strong>FA &#x26; Recovery</strong></td><td>Authenticate or recover your application account using using a one-time code</td><td></td><td><a href="/pages/5g7wJa7VXRQARQxiQMrS">/pages/5g7wJa7VXRQARQxiQMrS</a></td></tr></tbody></table>


# Email Actions

Configuring a form to send an email on submission

## Email <a href="#email-action" id="email-action"></a>

The email action allows sending an email when an event occurs on a form. With a multitude of options, users can configure this action to satisfy different workflows and use cases. Connect to your own Email transport, configure the email template, or dynamically attach files to the email.

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

## Settings

**Transport:** Select which email transport to use. These need to be configured in your project settings. Transports will not be available for selection if you haven’t configured them.

{% hint style="info" %}
When using the Form.io SaaS offering @ portal.form.io, ***you must set up your own Transport*****.** The default transport service provided by Form.io is no longer available. Please see the documentation on [**Email Integrations**](/dev/integrations/email-integrations) for instructions on how to proceed.
{% endhint %}

**From:** Enter the email address the email will be sent from.

**Reply-To: Email Address:** Set a different address the recipient will reply to.

**To:** Enter the email addresses to send to.

You can use field data from the form by using `{{ data.email }}` where the field's property name is email.

**Send a separate email to each recipient:** Each recipient designated in the TO field will receive an individual email

**Cc: Email Address:** Send a copy of the email to the listed email addresses

**Bcc: Email Address:** Send a blind copy of the email to the listed email addresses. Recipients will not see the other email addresses listed.

**Subject:** The subject of the email. By default, the Subject will interpolate the form title.

You may use other field data from the form using `{{ data.fieldname }}`

**Email Template URL:** The HTML template used to style and format your email content. By default, the email action will utilize the following HTML template to organize the content of the email:

<https://pro.formview.io/assets/email.html>

**Message:** The message in the email.

You may use field data from the form using `{{ data.fieldname }}`

**Rendering Method:** Determines how the email will render

*Dynamic* rendering utilizes formio.js to render the email.

*Static* rendering using the Nunjucks templating engine.

**Attach Submission Files:** Check this if you would like to attach uploaded files from the file component to the email.

**Attach PDF Files:** Check this if you would like to attach a PDF of the submission to the email. This will count toward your PDF Submission count for every email sent.

{% hint style="info" %}
If you are remotely deployed, please set the BASE\_URL=<https://yourdomain.com> to match the API server’s domain protocol and domain name for the formio-enterprise server
{% endhint %}

## Nunjucks Templating

All of the form fields are sent through a templating engine called [**Nunjucks**](https://mozilla.github.io/nunjucks/). It is recommended that you read through the documentation of this templating language to understand how it can be utilized to produce very complex templates for your emails using form data.

[**Click Here**](https://mozilla.github.io/nunjucks/templating.html) for the full Nunjuck Templating documentation.

Use the following *variables* which are provided to each template.

<table><thead><tr><th width="235">variable</th><th>Function</th></tr></thead><tbody><tr><td>data</td><td>The submission data which maps to the data object of the submission. Example: <code>{{ data.firstName }}</code> would map to the data provided in the "First Name" field if one is provided in your form.</td></tr><tr><td>id</td><td>The ID of the submission being submitted.</td></tr><tr><td><code>{{ data.[RESOURCE]Obj }}</code></td><td>Because all of the nested resources will only show their "template" data, every nested resource also has an object property assigned to the data to give you access to the full resource object assigned to that submission. For example, if you have a <strong>Customer</strong> resource field assigned to an <strong>Order</strong> resource, and you sent an email from the order. <code>{{ data.customer }}</code> would only show the templated customer, however <code>{{ data.customerObj }}</code> would contain the full customer object. In this case, you could type <code>{{ data.customerObj.data.email }}</code> to get the customers email address within the template.</td></tr><tr><td>content</td><td>This is the content within the Mail message section that you wish to inject within a template. This is useful if you wish to have a common template that all your emails use, and then use the "message" portion to construct the content within that template using <code>{{ content }}</code></td></tr><tr><td>form</td><td>The form object that this email is being sent from. <code>{{ form.components }}</code> would provide you with all the components within the form.</td></tr><tr><td>components</td><td>A flattened list of form components. Example, <code>{{ components.firstName.label }}</code> would print out the First Name component.</td></tr><tr><td>owner</td><td>The user who owns the form.</td></tr><tr><td>req</td><td>This is a stripped-down request object that contains the following parameters.<br><br></td></tr><tr><td>res</td><td>A stripped down response object that contains the following parameters.</td></tr><tr><td>mail</td><td>The current mail object being sent. Example <code>{{ mail.to }}</code> would contain the email address who the message is being sent to, which contains the following parameters.</td></tr></tbody></table>

### **Nunjucks Filters**

In addition to the core filters provided by Nunjucks, the following additional filters are also included for use within Emails.

<table data-header-hidden><thead><tr><th width="241">date</th><th>Prints out a date value as a readible date. See Nunjucks Date Filter for detailed documentation. Example {{ created | date("YYYY") }}</th></tr></thead><tbody><tr><td><code>date</code></td><td>Prints out a date value as a readible date. See <a href="https://github.com/e-picas/nunjucks-date-filter"><strong>Nunjucks Date Filter</strong></a> for detailed documentation. Example <code>{{ created | date("YYYY") }}</code></td></tr></tbody></table>

### **Nunjucks Macros**

In addition to template variables, we also provide a number of macros that can be used to easily render form submission information into your emails. These are as follows.

<table data-header-hidden><thead><tr><th width="313">{{ table(form.components, title) }}</th><th>Prints out a nested table of the form submission.</th></tr></thead><tbody><tr><td><code>{{ table(form.components, title) }}</code></td><td>Prints out a nested table of the form submission.</td></tr><tr><td><code>{{ submission(data, components) }}</code></td><td>Prints out a flat submission data table.</td></tr><tr><td><code>{{ value(key) }}</code></td><td>Prints out a readable value for a submission of a certain field. Example <code>{{ value('birthday') }}</code></td></tr><tr><td><code>{{ label(key) }}</code></td><td>Prints out the configured label for a certain field. Example <code>{{ label('birthday') }}</code></td></tr></tbody></table>

### Template Service

Considering that the template rendering is processor intensive, it is also possible to deploy the template rendering system as a separate service.

The library that governs the template rendering system is called Form.io Workers. This library can be found by going to [**https://github.com/formio/formio-workers**](https://github.com/formio/formio-workers). The deployed Form.io platform is also capable of offloading all email template processing to this separate micro-service. Within this library, you have the ability to either run this as a stand-alone Node.js service, or you can also use a tool such as [**Claudia.js**](https://www.claudiajs.com/).

For example, if you wish to push this into your own AWS Lambda function using Claudia, you can run the following within the directory.

```
npm run deploy
```

If you wish to see the command that is executed within the NPM script, you can open up the package.json file and see the "deploy" script within the scripts section. This uses Claudia to push this into AWS Lambda as a live endpoint.

#### **Endpoint**

Once the template service has been deployed, the "nunjucks" service can then be accessed using the following url.

`https://[TEMPLATE_SERVICE_URL]/worker/nunjucks?key=yourkey`

#### **Template Service Configuration**

The template service can be configured with the following environment variables. These variables can be provided within the `.env` file included with the source code of this library.

<table><thead><tr><th width="230.66666666666666">Environment Variable</th><th>Description</th><th>Example</th></tr></thead><tbody><tr><td>PORT</td><td>The port to bind to when running the service</td><td>3000</td></tr><tr><td>KEY</td><td>This is the secret key that is used to communicate to the template service via API. This key is used within the query parameter.</td><td>https://worker.yourdomain.com/worker/nunjucks?key=yourkey</td></tr><tr><td>LAMBDA</td><td>Tells the service if it is running within AWS Lambda or locally within a VM.</td><td>1 - To enable use lambda<br>2 - To use local install</td></tr></tbody></table>

Once you have the template service up and running, you can then tell the Form.io Enterprise Server to use this service with the TEMPLATE\_SERVICE environment variable like so.

```
TEMPLATE_SERVICE=https://worker.yourdomain.com/worker/nunjucks?key=yourkey
```

### Template Examples

The Email action Message carries a default **Nunjuck Macro** to produce an output of all field data within the submission which is found in the Message setting field of the action.

`{{ submission(data, form.components) }}`

This Macro works in conjunction with the HTML template found within the **HTML Email Template** field:

`https://pro.formview.io/assets/email.html`

The following examples will demonstrate how to add Nunjuck [**Tags**](#user-content-fn-1)[^1] and [**Macros**](#user-content-fn-2)[^2] to your own custom template messages. These examples will use [**HTML**](https://www.w3schools.com/html/html_tables.asp) to format the content of the email inside a readable table.

Each example utilizes the following form which can be [**Imported**](https://help.form.io/form-building/form-settings#copy-a-form) into your own project using the Form Embed URL.

[**`https://khvenypsypifjpi.form.io/expensereporting`**](https://khvenypsypifjpi.form.io/expensereporting)

<figure><img src="/files/y4vedowLRweZ3KUTwQf3" alt=""><figcaption><p>Expense Form Example</p></figcaption></figure>

#### **Extracting Field Submission Data**

In this example, the email template will use Nunjuck Macros to interpolate the **Employee Name**, **Employee ID**, and **Department** field data from the submission and output the information into an HTML table inside the email message.

<figure><img src="/files/OgNoWTnY6VCQ1Db0moU3" alt="" width="563"><figcaption></figcaption></figure>

Add the following code to the Message field within the Email Action settings.

<pre class="language-javascript" data-full-width="true"><code class="lang-javascript"><a data-footnote-ref href="#user-content-fn-3">&#x3C;h3>&#x3C;b>User Information&#x3C;/b>&#x3C;/h3></a>
<a data-footnote-ref href="#user-content-fn-4">&#x3C;table align="center" style="width:75%;"></a>
  &#x3C;tr>
    &#x3C;td>&#x3C;b><a data-footnote-ref href="#user-content-fn-5">{{ label("employeeName") }}</a>&#x3C;/b>&#x3C;/td>
    &#x3C;td><a data-footnote-ref href="#user-content-fn-6">{{ value("employeeName") }}</a>&#x3C;/td>
  &#x3C;/tr>
<strong>  &#x3C;tr>
</strong>    &#x3C;td>&#x3C;b><a data-footnote-ref href="#user-content-fn-7">{{ label("employeeId") }}</a>&#x3C;/b>&#x3C;/td>
    &#x3C;td><a data-footnote-ref href="#user-content-fn-8">{{ value("employeeId") }}</a>&#x3C;/td>
  &#x3C;/tr>
  &#x3C;tr>
    &#x3C;td>&#x3C;b><a data-footnote-ref href="#user-content-fn-9">{{ label("department") }}</a>&#x3C;/b>&#x3C;/td>
    &#x3C;td><a data-footnote-ref href="#user-content-fn-10">{{ value("department") }}</a>&#x3C;/td>
  &#x3C;/tr>
&#x3C;/table>
</code></pre>

#### **Using For Loop To Output Field Submission Data Inside Arrays**

The **`for`** tag is a Nunjuck tag that iterates over arrays and dictionaries. This example demonstrates how to interpolate data from fields inside an array (Data Grid, Edit Grid, etc) and output that data into the email message. Array data is referenced differently than other types of data, because of this, we are unable to use the Nunjuck Macro provided in the previous example and must set up a For Loop inside the message template.

To reference array data:

1. Create a [**For Loop**](https://mozilla.github.io/nunjucks/templating.html#for) provided by the Nunjuck templating documentation.\
   [`{% for X in X %}`](#user-content-fn-11)[^11]
2. Set the array data inside the loop. Data inside of Data Grids or Edit Grids is referenced using the row attribute.\
   [` {% for`` `` `**`row`**` `` ``in X %} `](#user-content-fn-12)[^12]
3. Reference the Array property name within the loop. In this example our Data Grid property name is expense.\
   [` {% for row in`` `` `**`data.expense`**` `` ``%} `](#user-content-fn-13)[^13]
4. Now we can reference the individual fields within the array. Use the `row` variable and the API Property Name of the field\
   [`{{ row.date }}{{ row.expenseType }}{{ row.amount }}`](#user-content-fn-14)[^14]
5. Close out the For Loop\
   ` {%`` `` `**`endfor`**` `` ``%} `
6. Here is an example of a For Loop being used within an HTML table and Nunjuck Macro. The Table will create columns for the Expense Data, Expense Type, and Amount. The Nunjuck Macro will interpolate the Label of these fields from the Form and present them as the column headers. The For Loop lists all the component row data inside the Expense Data Grid and presents the row data within the HTML table.

<figure><img src="/files/qdJQ2YbpUTLgOCmZZ5ab" alt="" width="563"><figcaption></figcaption></figure>

Add the following code to the Message field within the Email Action settings.

<pre class="language-javascript"><code class="lang-javascript">&#x3C;center><a data-footnote-ref href="#user-content-fn-3">&#x3C;h3>&#x3C;b>Expense Report&#x3C;/b>&#x3C;/h3></a>&#x3C;/center>
<a data-footnote-ref href="#user-content-fn-4">&#x3C;table align="center" style="width:75%;"></a>
&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-15">{{ label("date") }}</a>&#x3C;/th>
&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-16">{{ label("expenseType") }}</a>&#x3C;/th>
&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-17">{{ label("amount") }}</a>&#x3C;/th>


&#x3C;/table>
</code></pre>

**If tag for conditional data output inside the email content**

The **If** tag tests a condition and lets you selectively display content inside the email. It behaves exactly as javascript's `if` behaves.

In this example, the Manager field data should be included in the email content when the field contains data.

1. Add an **If** tag inside your message template\
   [`{% if X %}`](#user-content-fn-18)[^18]
2. Add the condition statement inside the tag\
   [`{% if data.manager !== "" %}`](#user-content-fn-19)[^19]
3. Add the output of the condition. If the Manager field has a value, the condition will output the Label and data Value of the field inside the HTML table

   <pre><code>&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-20">{{ label("manager")}}</a>&#x3C;/th>
   &#x3C;tr>
   &#x3C;td><a data-footnote-ref href="#user-content-fn-21">{{value("manager")}}</a>&#x3C;/td>
   &#x3C;/tr>
   </code></pre>
4. Close out the If tag\
   [`{% endif %}`](#user-content-fn-22)[^22]

<figure><img src="/files/nQJzylkiC2cSK3ckPVr2" alt="" width="563"><figcaption></figcaption></figure>

<pre><code>&#x3C;center><a data-footnote-ref href="#user-content-fn-3">&#x3C;h3>&#x3C;b>User Information&#x3C;/b>&#x3C;/h3></a>&#x3C;/center>
<a data-footnote-ref href="#user-content-fn-4">&#x3C;table align="center" style="width:75%;"></a>

&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-23">{{ label("manager")}}</a>&#x3C;/th>
&#x3C;tr>
&#x3C;td><a data-footnote-ref href="#user-content-fn-24">{{value("manager")}}</a>&#x3C;/td>
&#x3C;/tr>
&#x3C;/table>

</code></pre>

**Using If tag inside a For Loop**

In some cases, you may want to incorporate **If** tags where the condition is based on fields inside an array. In this case, the If tag must be set inside the For loop of the message template.

Within the form, there is a field inside the Expense DataGrid called **Other Expense** that will conditionally display when **Other** is selected from **Expense Type** dropdown. In this example, the **Other Expense** data should be included in the email content only if the Other Expense field is conditionally displayed on the form.

There are two **If** tags being used in the following example. The first will display the Other Expense Label within the header of the HTML table. The second will display the Other Expense submission value within the corresponding row of the table.

1. Add a For Loop\
   `{% for X in X %}`
2. Within the For Loop, add the If tag inside the HTML table row (line 12)\
   [`{% if row.expenseType === "other" %}`](#user-content-fn-25)[^25]
3. Add the corresponding result inside the tag (line 15). The row variable is used here to reference data within an array.\
   `{{ row.otherExpense }}`
4. Close out the If tags (line 14)\
   `{% endif %}`

<pre class="language-javascript" data-line-numbers><code class="lang-javascript"><strong>&#x3C;center><a data-footnote-ref href="#user-content-fn-3">&#x3C;h3>&#x3C;b>Expense Report&#x3C;/b>&#x3C;/h3></a>&#x3C;/center>
</strong><a data-footnote-ref href="#user-content-fn-4">&#x3C;table align="center" style="width:75%;"></a>
<a data-footnote-ref href="#user-content-fn-26">&#x3C;th align="left"></a><a data-footnote-ref href="#user-content-fn-27">{{ label("date") }}</a>&#x3C;/th>
&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-28">{{ label("expenseType") }}</a>&#x3C;/th>
&#x3C;th align="left"><a data-footnote-ref href="#user-content-fn-29">{{ label("otherExpense") }}</a>&#x3C;/th>
&#x3C;th align="left">{{ label("amount") }}&#x3C;/th>


&#x3C;/table>
</code></pre>

**Final Example**

The example below incorporates all of the previous examples using Nunjuck Macros, For loops, and If tags.

<figure><img src="/files/hYhdRPyX2M7WoEjqIHL2" alt="" width="463"><figcaption></figcaption></figure>

```javascript
<h3><b><center>User Information</b></h3></center>
<table align="center" style="width:75%;">
  <tr>
    <td><b>{{ label("employeeName") }}</b></td>
    <td>{{ value("employeeName") }}</td>
  </tr>
  <tr>
    <td><b>{{ label("employeeId") }}</b></td>
    <td>{{ value("employeeId") }}</td>
  </tr>
  <tr>
    <td><b>{{ label("department") }}</b></td>
    <td>{{ value("department") }}</td>
</tr>
<tr>
   {% if data.manager !== "" %}
    <td><b>{{ label("manager")}}</td></b>
    <td>{{value("manager")}}</td>
    {% endif %}
</tr>
</table>
<br>
<br>
<center><h3><b>Expense Report</b></h3></center>
<table align="center" style="width:75%;">
<th align="left">{{ label("date") }}</th>
<th align="left">{{ label("expenseType") }}</th>
<th align="left">{{ label("otherExpense") }}</th>
<th align="left">{{ label("amount") }}</th>
{% for row in data.expense %}
<tr>
<td>{{ row.date }}</td> 
<td>{{ row.expenseType }}</td>
<td>
{% if row.expenseType === "other" %}
{{ row.otherExpense }}
{% endif %}</td> 
<td>{{ row.amount }}</td> 
</tr>
{% endfor %}
</table>
```

## Video

{% embed url="<https://youtu.be/DlzLg4oa9bo>" %}

[^1]: Tags are special blocks that perform operations on sections of the template

[^2]: Macros can be used to easily render form submission information into your emails

[^3]: HTML Header

[^4]: HTML Table

[^5]: Nunjuck Macro outputting the label of the Employee Name<br>

    employeeName is the property name of the field

[^6]: Nunjuck Macro outputting the submitted data value of the Employee Name<br>

    employeeName is the property name of the field

[^7]: Nunjuck Macro outputting the label of the Employee ID<br>

    employeeID is the property name of the field

[^8]: Nunjuck Macro outputting the submitted data value of the Employee ID<br>

    employeeID is the property name of the field

[^9]: Nunjuck Macro outputting the label of the Department<br>

    department is the property name of the field

[^10]: Nunjuck Macro outputting the submitted data value of the Department<br>

    department is the property name of the field

[^11]: Nunjuck Macro For Loop

[^12]: Add the variable the For Loop will be referencing

[^13]: The array field the For Loop is referencing.

    expense is the Property Name of the Data Grid being used.

[^14]: The Property Names of the fields nested inside the Expense Data Grid

[^15]: Nunjuck Macro outputting the label of the Date<br>

    date is the property name of the field

[^16]: Nunjuck Macro outputting the label of the Expense Type<br>

    expenseType is the property name of the field

[^17]: Nunjuck Macro outputting the label of the Amount<br>

    amount is the property name of the field

[^18]: Nunjuck If tag

[^19]: Use the field's Property Name and data variable within the If tag to reference field data.<br>

    Javascript to check for an empty string

[^20]: Nunjuck Macro outputting the label of the Manager<br>

    manager is the property name of the field

[^21]: Nunjuck Macro outputting the submitted data value of the Manager<br>

    manager is the property name of the field

[^22]: Close out If tag

[^23]: Nunjuck Macro that interpolates the Manager field Label

    manager is the Property Name of the Manager field

[^24]: Nunjuck Macro that interpolates the Manager field submission Value

    manager is the Property Name of the Manager field

[^25]: Nunjuck If tag.

    row is being used to reference data within an array

    expenseType is the Property Name of field the condition is based on

    other is the value of the Expense Type field the condition will execute on.

[^26]: Header Cell within the HTML Table

[^27]: Nunjuck Macro interpolating the Date field Label

    date is the Property Name of the Data field

[^28]: Nunjuck Macro interpolating the Expense Type field Label

    expenseType is the Property Name of the Data field

[^29]: If tag condition result which will output the Other Expense Label within the HTML Table column Header


# Google Sheets Actions

The Google Sheets action maps field data from a form to an external Google Sheet document. The Form Builder has control over what data is saved to which column within the document. This action can be very useful if an ongoing report is needed to track submission data from a form to a spreadsheet.

{% hint style="info" %}
Before the Google Sheet action can be used, a Google Integration must first be established before the Action can connect with the user's Google Drive.

[**Click Here**](/dev/integrations/google-developer-console) to establish a Google Integration with a Form.io project.

[**Click Here**](/dev/integrations/google-developer-console#enabling-google-apis) to enable Google Drive
{% endhint %}

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

## Settings

**Sheet ID:** The ID of the Google Sheet being used. The ID is the string of characters found in the URL endpoint of the Google Sheet document.

**Worksheet Name:** Name of the Worksheet, or tab, within the Google Sheet document. By default, the name will be Sheet1

**Start Row:** The row the data will start to merge into. By default, this is set to 2 accounting for row 1 is reserved for the field headers.

**Google Sheet Fields:** The setting fields here represent the fields on your form. Each field can be mapped to a column represented by the letter header within the Google Sheet document.

**External ID Type:** The name to store and reference the external Id for this action. This is useful when using several Google Sheets actions and should specify a unique *External Id Type* to each Google Sheet action to avoid undesirable results.

## Walkthrough

To set up integration between a form and a Google Sheet document, you will first need to establish the [**Google Drive integration**](/dev/integrations/file-storage#google-drive). After the integration is complete, add a Google Sheets action to the form.

On the Actions tab, select “Google Sheets” from the Action list.

![](/files/2SFuHG1rWL4KUFCGIHCL)

Open the Google Sheet you wish to use and copy the Spreadsheet ID (string of characters found in the Spreadsheet URL) and Sheet Name (name of the tab within the sheet).

Paste the Sheet ID and Sheet Name within the Action. Next, map the fields on your form to columns in the Sheet. You can find Spreadsheet keys at the top of Spreadsheet columns. For each field, specify the column key you wish to map the data to e.g. adding ‘A’ in \[First Name] field will post the submitted data for that field in Column A of the spreadsheet.

![](/files/ZGDC7nMoJMoTDJxf8T7u)

Now it’s time to test our settings. Go to the view tab of your form and submit the form with relevant data in the fields.

![](/files/Nesjzi3YFuUNTkf7prQ7)

You should see the field titles are automatically created in the Google Spreadsheet and the correct form data is added to the columns configured in the action form fields. Any additional form submissions will add data to the subsequent rows.

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

## Video

{% embed url="<https://youtu.be/lmW-mr9z-pg>" %}


# Group Assignment Actions

The Group Assignment action grants access to certain users who belong to a certain "group" Resource within your project. A **Group** can be defined as a separate Resource that is then assigned to different users, thereby placing those users into different permission contexts. In order to establish a permission system based on these groups, follow the Walkthrough guide below.

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

## Settings

**Group Resource:** The Select Resource field on your form that maps to the Group Resource.

**User Resource:** The Select Resource field on your form that maps to the User Resource. Users will join the selected Group upon submission.

**User Role:** The Select Resource field on your form that maps to the Role Resource. Users will carry the User Role that was selected upon submission

## Walkthrough

[**Click here for more information on Group Assignments workflows**](/admin/roles-and-permissions/field-based-resource-access)

### Group Permissions

In addition to providing access based on Roles within a project, you can also grant access to certain users who belong to a certain "group". A **Group** can be defined as a separate Resource that is then assigned to users, thereby placing those users into different contexts. In order to establish a permission system based on these groups, we must first setup our project to enable Group structure. We will start by creating a Group resource.

#### Create a Group Resource

In order to take advantage of the group permission system, you must first create a "group" resource. A group can really be defined as any entity that is used to coalesce different sets of users into different groups. Here are some good examples of what would be defined as a Group.

* **Department** - Used to place employees in their own departments.
* **Team** - Could be used to place athletes into their teams.
* **Class** - Could be used for education to collect teachers and students together into a "class" group.

For this generic example, however, we will just call our group "Group" which can be done by creating a new resource, and we will just add a single Text Field called "Name".

![](/files/bGK0dN5u2109cv7kmWMY)

Once this group is created, we can now create a few example groups by simply using this resource and submitting a few records. We will just create two new groups called, "Teachers" and "Students"

![Viewing the data of group to see our two "groups" called Teachers and Students.](/files/4Ens9sYH4lQa7BY6Akuq)

We can now create our "join" resource to bring users and groups together.

#### Creating a Join Resource

To create a many-to-many relationship between Users and Groups (where users can be associated with many groups, and vice-versa) we will create another Resource that will serve the sole purpose of "joining" these two resources together. This is typically called a **Join Resource** and is very powerful in establishing a many-to-many relationship between two resources.

{% hint style="info" %}
A one-to-many relationship is also possible by simply adding the "Group" resource as a field that belongs on the User resource, but for this example, we will cover the more common use case of using a join resource.
{% endhint %}

To create this Join Resource, we will do the following.

1. Create a new **Resource** and call it **UserGroup**
2. Drag and drop a **Select** component
3. Give the component a label of **User**
4. Click on **Data** tab, and then select **Resource** under **Data Source Type**.
5. Next, select **User** as the resource.
6. Scroll down and then type the following for **Item Template.** `<span>{{ item.data.email }}</span>`
7. Press **Save** to save the field on the form.
8. Repeat steps 2 - 7, but this time do it for the **Group** resource. Make the **Item Template** as `<span>{{ item.data.name }}</span>`

Now save this resource.

![A Join Resource to bring Users and Groups together](/files/PMerKmqTpzxrWLvz06V9)

Next, you will click on the **Actions** tab for this resource, add a new Action called **Group Assignment** and then click on **Add Action** button. Under the action settings, for **Group Resource**, select **Group** and for the **User Resource**, select **User.**

![Make sure to add a Group Assignment action with the following settings.](/files/j4FzYFgBisNonG5pXFG2)

Next click **Save Action** to add this action to the form.

![UserGroup resource with Group Assignment action.](/files/tPbhjpYfDhjlg8jDqADY)

We can now create a few submissions in this resource (by clicking the **Use** tab) so that we can associate some users with some groups. Here is an example of the submission data after we have done this.

![Adding some users to groups](/files/mtBr4E7QIiWA17fxaEsE)

### Assigning Group Permissions

The next thing we need to do is to add a Group to a form (as a field), and then provide access to that form based on the group that the user belongs to. For example, we could create an **Evaluation** form, and then add the following Group as a field to that form.

![Creating a form that contains the Group as a select field](/files/KsKYLka7KkbgBFlKPVBD)

Now that you have the field added to your form, we can now edit the **Access** tab and configure the following under the **Field Based Resource Access** section.

![Giving groups "read" access to the form submissions.](/files/FToYbJUh0FPM3B0JGSpT)

This configuration basically says the following.

> Any students who create evaluations can read other students evaluations, but not teachers evaluations. Any teachers who create evaluations can read other teachers evaluations, but not student evaluations.

This is how you can enable groups of users to have different access than other groups of users based on their associations with other resources within a Form.io project.

{% hint style="info" %}
Group permissions function by assigning the Group ID (submission id) as a "role" that is added to the user's submission object. This can be seen by viewing the user's submission JSON and viewing the "roles" property which will contain any group IDs that the user has been assigned.
{% endhint %}

## Group Roles

In addition to allowing Groups to be established, it is also possible to establish roles, where further categorization of users can be made within a single group. For example, if you wish to have a Group defined as a **Classroom,** the Group Roles system allows you to assign users to a Classroom, but then choose if they are a Teacher or a Student within that classroom, and then grant separate permissions based on their role within the Group.

This is configured exactly as you would configure the Group Permissions above, but with just a few differences.

* When you create your **Join Resource**, you will need to create a field that will be used to establish the "Roles" within that group. This can simply be a Select dropdown with the Values of that select dropdown showing the roles you wish to provide.

![Adding a Group role to the Join Resource](/files/hhx0UqssVVEtG7hGIWtf)

* When you configure the **Group Assignment** action, you will now want to select this new field as the Role.

![](/files/fbEPBDNHKnXlHjsgfCip)

* Finally, when you assign the permissions of the Group to the form, you will want to assign which role within the form can have which permission.

![](/files/r1UBCOA8yw4jiTyBDQ4Q)

##


# LDAP Login Actions

Configuring a a form to use LDAP Login actions for authentication

LDAP Authentication integration provides the ability to authenticate users directly against an LDAP service such as OpenLDAP or Active Directory. The LDAP Login action connects the Username and Password credentials from the form to the LDAP directory.

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

## Settings

**Username Field:** The Username field from the form mapped to the username field from the LDAP directory

**Password Field:** The Password field from the form mapped to the username field from the LDAP directory

**Passthrough:** If checked, any failures except for a failure to Bind the user account, will be ignored and the login information will be passed to the next form action. This allows using both LDAP and the Form.io Login action on the same form.

**LDAP Property:** Group name within the LDAP directory

**Value:** Given Role from the LDAP Directory

**Role:** Form.io role the Property group and Value will map to.

## Walkthrough

{% hint style="info" %}
LDAP Integration must first be configured within your Project settings before the workflow can function.

[**Click Here for more information on integration setup.**](/dev/authentication-and-authorization/ldap)
{% endhint %}

### Build an LDAP Login Form

Create a new form that will be used to Login to LDAP:

1. Click on **New Form**, and then add a User Name **text field** and a **Password** field named Password:

![](/files/k6GZF0TeImRKomwHyOEy)

2. Click the **Create Form** button to create the new form.

Next, ensure that Anonymous users are able to submit this form.

3. Click on the **Access** settings and add the Anonymous role to the Create Own Submissions permission.

![](/files/FxQaxpNI9CgNbQDKAuYL)

### Add the LDAP Login Action

1. Navigate to the **Actions** section of the form.
2. Remove the Save Submission Action by clicking the red trash can icon.
3. Select **LDAP Login (Premium)** then click **Add an action** button.

![](/files/4DeDsIYLqCUM5vrXcna4)

### Configure the LDAP Login Action

1. Within the LDAP Login Action, configure the following parameters:

   1. **Username field -** Map to the Form's User Name component.
   2. **Password Field -** Map to the Form's Password component.
   3. **LDAP Property -** Leave blank
   4. **Value** - Leave blank
   5. **Role** - Select **Authenticated**

   This will assign the Authenticated role to all LDAP users who authenticate through the form.

![](/files/MRcFVdE4P6Z3c1IOwqfO)

{% hint style="info" %}
When using Passthrough authentication, any failures except for a Failure to Bind the User Account, will be ignored and the login information will be passed to the next form action. This allows using both LDAP and the Form.io Login action on the same form.
{% endhint %}

### Assign Roles

To assign additional roles to the usesr upon Authentication, map any LDAP properties to user roles:

1. Fill in the **property** with the corresponding property that maps to the desired role.
2. Fill in the corresponding **value**.
3. Select the **Role** that will be assigned to any users who match the criteria.\
   For example:

   * **LDAP Property**: *group*
   * **Value**: *Admins*
   * **Role**: *Admin*

   Would assign the Admin Form.io role to any members of the LDAP Admins group.

{% hint style="info" %}
Leaving **LDAP Property** and **Value** will to assign the role to all LDAP accounts who authenticate.
{% endhint %}

The user’s DN is also mapped to the list of properties. For example, if the DN is `dn=myname,ou=admins,dc=example,dc=org` you can do:

* **LDAP Property**: *ou*
* **Value**: *admins*
* **Role**: *Admin*

4. **Save** the changes before proceeding.

## Testing LDAP Login

To test the LDAP login, perform the following API request within **Postman**:

![](/files/-MdH90sm-iqc0TYmfuDp)

Here you will see that the **Authenticated** role has been assigned to the user object.


# Login Actions

Configuring a Login action to fire on form submission

## Login

The Login Action is typically connected to a User-based resource (like the default User or Admin Resources that come with each project) and Email/Password fields from the Login form are then mapped to the Email/Password field from the connected Resource using the Login action settings.

When the Action is executed, the Email/Password data is then verified from the Resource Data Base. If a match is found, the user will then be authenticated into the application.

<figure><img src="/files/X2pQsC69CD4KsX7xsguQ" alt=""><figcaption><p>Login action mapped to the User Resource</p></figcaption></figure>

## Settings

**Resources:** The Resource the action will reference for matching Email/Password information.

**Username/Password Field:** Map the fields from your form to the connected resource to validate a match for Login authentication.

**Maximum Login Attempts:** The number of times a User can fail a Login attempt before being locked out. Use 0 for an unlimited number of attempts.

**Login Attempt Time Window:** The window of time in seconds to count the login attempts. Once the User is outside of the time threshold, the Login Attempt number is reset, as long as they have not been locked.

**Locked Account Wait Time:** The amount of time in seconds a person needs to wait before they can try to log in again.

## Video

{% embed url="<https://youtu.be/h9pvYHWkJD0>" %}


# OAuth Actions

Using OAuth actions to authenticate a Form user.

The OAuth action supports user authentication within the application against an OAuth provider. When a user authenticates, a window prompt will request the user to log into the configured OAuth provider’s website. The user will authenticate the user into the application with a successful login from the OAuth provider. This allows users to register and log in to the application without having to have an account within the application Project.

<figure><img src="/files/80X5OLMmtsglPJMQAhfr" alt=""><figcaption></figcaption></figure>

## Settings

**OAuth Provider:** The OAuth Provider to authenticate against. This is the service that users will log into when authenticating via OAuth. You will need to register your application with these providers before you can use OAuth. See the [**OAuth guide**](/form-building/actions) for more information. We currently support the following OAuth providers:

* [**GitHub**](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps)
* [**Facebook**](https://developers.facebook.com/documentation/facebook-login/web)
* [**Office 365**](https://www.microsoft.com/en-us/microsoft-365/compare-all-microsoft-365-products?activetab=tab:primaryr2)

**Action:** The action to perform after the user has authenticated against the OAuth provider. The available Actions are listed below:

* **Remote Authentication***:* This will log a user in based on their remote user account. Unlike the rest of the actions, it does not require creating a user resource submission in form.io. All permissions and ownership still work.
* **Login Existing Resource:** This will attempt to authenticate an existing resource via OAuth. Use this action for forms like Login forms. This will search for a user account that is linked to the authenticated OAuth provider account, and log them in.
* **Register New Resource** This will create a new submission and perform authentication against the new resource. Use this action for forms like Registration forms. This will create the user account, link the authenticated OAuth provider account, and log them in.
* **Link Current User:** This will link an OAuth provider account to the currently logged-in user. Use this to allow users who have authenticated via the [Authentication Action](/form-building/actions#action-authentication) with an email and password to also log in to their account via OAuth.

**Role:** The selected role will be added to all new resources created by the form with this Authentication Action.

**Sign-in with OAuth Button** In order to use the OAuth Action in a form, you must choose a [**Button component**](/form-building/actions#button) with the action setting `OAuth` to start the OAuth sign-in process. When a user clicks the provided button, the OAuth authentication process will begin by opening a popup of the OAuth provider login page.

Please note - When embedding the form into the renderer, append "?live=1" parameter at the end of the form embed URL to allow for the OAuth action to trigger properly

**Autofill Fields:** Depending on which OAuth provider you select, and if you select the *Register New Resource* action, a number of Autofill Field options may appear. These settings allow you to automatically retrieve data from the OAuth provider account that is used to authenticate and fill in fields in your form before the new resource is created. For example, a GitHub OAuth Registration form may use the Autofill Email Field to assign the email of the GitHub account that was used to authenticate into a field of the new Resource that is created.

Autofill Fields will not always guarantee that they will find a value to fill, as the OAuth provider account may not have any information. For example, a Facebook account may not always fill the Autofill Email Field because some Facebook accounts are created with phone numbers.


# Role Assignment Actions

Setting up a form action to add, modify, or remove a role associated with a submission

The **Role Assignment Action** adds, modifies, or removes roles associated with the submission when an event occurs on a form. A common use case for the Role Assignment action is adding the action on a Registration form to grant users certain roles after they register. Those roles will then work in tandem with Form.io's authentication system.

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

## Settings

**Resource Association:** The resource association will determine if a new or existing resource will be modified.

**Action Type:** What type of role assignment action to take.

Add Role: Adds the given Role to the submission record.

Remove Role: Removes the given Role from the submission record.

**Role:** The role to use when performing the role assignment. Roles are managed from the Access section of the project found on the left-hand navigation bar.

{% hint style="info" %}
The Role Assignment Action requires a Resource Form component with the API key, ‘submission’, to modify existing Resource submissions
{% endhint %}

## Video

{% embed url="<https://youtu.be/T_K7jJwKzog>" %}


# Save Submission Actions

Configure an action to record submission data against a Form or esource.

This action dictates what Resource and related Resource fields the form data will save to. Every form or Resource created will carry a Save Submission action. When left unmodified, the action will save the data to itself by default.

Mapping the Save Submission action to other Resources allows a Form to feed a resource database. The most common example is a Registration form. When a user Registers, the submitted data most likely will need to be saved to some sort of User Resource to build a User database collection.

<figure><img src="/files/SuoTMc6SqRrteKJhJMvt" alt=""><figcaption><p>Save Submission action mapped to the User Resource</p></figcaption></figure>

## Settings

**Save Submission To:** Select which Resource the submission data should map to. When left blank (default), the submission will save to itself.

**Resource Property:** Set a Property to the mapped Resource that will be assigned to.

**Simple Mappings:** When a Resource is selected, the available fields from that Resource will become available for mapping in the Simple Mappings section. Clicking a field will present a Dropdown of fields from the Form the action is attached to where fields from your Form are mapped to fields from the Resource.

**Transform Data:** Use the Transform Data if you are trying to map fields inside complex data structures like EditGrids, Containers, Nested Forms, etc. Available variables are Submission and Data.

## Walkthrough

In this example, we are going to configure a Save Submission action on a Registration form to map submission data to a User Resource. In turn, as the Registration form collects submissions, the Resource will build its database of Users within the project.

To start, **create a Resource** called Users and add the following fields:

Email - Email

Password - Password

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

Next, create a Form called Registration. **Add the following fields**:

First Name - Textfield

Last Name - Textfield

UserName - Textfield

Email - Email

Password - Password

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

Click the Action tab for the Registration form and add another **Save Submission action**. Within the Action settings, click the Save Submission To dropdown and select the **User resource**. Next, **map the Email and Password fields** from the form to the Resource fields presented in the Save Submission Action. Save your action.

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

To test the action, **Use** the Registration form and make a **submission**.

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

The submission should map to the User Resource, creating a submission record. To verify this, navigate to your User resource and click the **Data tab**. There should be a new submission entry from the Registration form.

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

{% hint style="info" %}
Encrypted password data will not display when viewing a submission.
{% endhint %}

## Video

{% embed url="<https://youtu.be/W9ht8i5u8Kk>" %}


# SQL Connector Actions

The SQL Connector Action has been deprecated

The SQL Connector Action has been deprecated. For alternatives, refer to the[ feature deprecation notice.](/dev/sql-connector)


# Two-Factor Auth & Recovery Actions

The 2FA Authentication action allows users to log in to your Portal base project or application using a one-time 6-digit code from an authentication provider.

Please note, the Portal Base project for deployed users will have Two-Factor Authentication preconfigured.

{% hint style="info" %}
When utilizing 2FA for your own project (not Base Portal), provide read access permissions for your users to the Two-Factor Authentication Settings Form.
{% endhint %}

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

## Settings

**Code:** Field on the form (typically a Textfield) to provide the 6-digit authentication code.

**Recovery Code:** One-time recovery code to authenticate users.

## Walkthrough

[**Click Here for a full walkthrough of how to setup Two-Factor Authentication**](/dev/authentication-and-authorization/resource-based-authentication/two-factor-authentication)


# Webhook Actions

Configuring a form action to interact with an external service via webhook

The Webhook action connects Form submissions into other applications or databases by providing a means to call an external API with a payload containing the form submission data in real-time. In order for the Webhook action to function properly, the API endpoint must be accessible by the same network as the Form.io deployment.

{% hint style="info" %}
Webhooks execute when using a form. They do not execute when building/editing a form within the Developer Portal. To test Webhooks, the form should be launched using the FormviewPro Application, or embedded within an application.
{% endhint %}

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

## Settings

**Request Method:** This is the REST Verb that will be used to make the request. If set to Match (or blank) it will use the request method that came with the request. For example, a Create request will have the Post method. Below are the available request methods:

*Get, Post, Put, Delete, Patch*

**Request URL:** The URL of the external system that will handle the webhook. This should be accessible to the form.io server.

**Forward Headers:** If checked, all of the headers received by the form.io server will be forwarded to the webhook.

**Authorize User:** If you are using Basic Access Authentication for the webhook request, enter the username here.

**Authorize Password:** If you are using Basic Access Authentication for the webhook URL, enter the password here.

**Additional Headers:** You can add additional headers as needed by providing the Header and Value. These might include an Authorization header or Content-Type.

**Request Payload:** By default, the request payload will contain an object with the following information:

```
{
  request: request, // an object containing request body to the form.io server.
  submission: submission, // an object containing the submission object from the request.
  params: params, // an object containing the params for the request such as query parameters or url parameters.
}
```

You can use the transform payload javascript to modify the contents of the payload that will be sent in this webhook. The following variables are also available: headers

**Transform Payload:** You can modify the request payload by writing custom javascript code. There are available variables that can be used to aggregate into a custom object as desired. Whatever is placed into the payload will be sent as the body of the request.

**Wait for Webhook Response**

By default, webhook actions will not wait until a response is received to continue to the next form action. If you check the box labeled "Wait for the webhook response before continuing actions," the form submission process will wait for a webhook response before continuing and return the results to the front end in the submission's metadata field. Any errors received from webhooks whose responses are being awaited will stop the form submission process and be displayed to the form user.

**External Id Type and Path**

If the webhook endpoint creates a data object in the external system, there is often an id created and returned in the response. If you want to save this id and associate it with the submission in Form.io, you can specify a type and id path here. The **External Id Type** is the reference key of the external service's database (e.g. "github"). The **External Id Path** is the path to the id field in the external service's response object. For example, in the response below (returned from AirTable), the path would read *records\[0].id*. If you use the same External Id Type in multiple webhooks, any subsequent changes to the id field will be updated in the Form.io submission data.

```
{
	“records”: [
		{
			“id”: “recZ37x123HWzDLaJ”,
			“createdTime”: “2022-09-24T01:31:25.000Z”,
			“fields”: {
				“Customer”: “Joe Smith”
			}
		}
	]
}
```

**Retry Request**

If the webhook fails the first time, it is possible to retry the request. To use a retry request, you need to set the type of repeat, the maximum number of attempts, and the initial delay in milliseconds.

**Retry Type:** If the initial request fails, the calculation of the delay between further attempts will be calculated based on the type of repeat.

* Constant - the delay between attempts is constant and equal to the initial delay (e.g., 200ms, 200ms, 200ms, etc.)
* Linear - the delay between attempts increases linearly (e.g., 100ms, 200ms, 300ms, etc.)
* Exponential - the delay between attempts increases exponentially (e.g., 100ms, 200ms, 400ms, 800ms, etc.)
* Jitter - mitigate correlations and improve the performance by adding randomness (e.g., 170ms, 275ms, 196ms, 511ms, etc.)
* Exponentially Jitter - mitigate any corrections, fewer spikes, and a smoother distribution than Jitter type (e.g., 196ms, 267ms, 595ms, 1132ms, etc.)

**Number of attempts:** The maximum number of additional request attempts if the request fails. If the request is successful, the retry request is stopped.

**Initial Delay:** The initial delay between the initial request and the first additional attempt. The delay is calculated based on the retry type.

## Webhook Testing

In order to ease development and testing around your webhooks, we've created an example application called [**Webhook Receiver**](https://github.com/formio/formio-webhook-receiver). You can install this application on your local machine by executing the following commands in your terminal.

```
npm install
node index.js
```

This will run the receiver on your local machine. To easily connect services running on your local computer to the wider internet, we recommend using a tool (often called a "tunneler") such as [**ngrok**](https://ngrok.com/). Once you have a ngrok account and the software [**installed**](https://ngrok.com/download), you will need to expose the Webhook Receiver application running on your local machine by running the following command in your terminal:

```
ngrok http 4001
```

You should now see the tunnel address that's been created:

```
Version                       2.1.14
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://941a7c65.ngrok.io -> localhost:4001
Forwarding                    https://941a7c65.ngrok.io -> localhost:4001
```

This indicates that the address `http://941a7c65.ngrok.io` will tunnel to the Webhook Receiver application running on your local machine. Once the tunnel is running, configure a Webhook Action on your form with the following settings:

* **Webhook URL**: <http://941a7c65.ngrok.io>
* **Authorize User**: test
* **Authorize Password**: password123

(The username and password can be changed in the `config.json` file of in the Webhook Reciever's root directory.)

You can now submit the form and see the data come through your local machine!

## Sample Payload

Here's a sample of what the default request payload looks like on a form that has a text field named "textField" and a number field named "number":

```
{
  request: {
    data: { textField: 'Test value', number: 12345, submit: true },
    owner: '61c5e59add38c4e4a356acb0',
    access: [],
    metadata: {
      timezone: 'America/Chicago',
      offset: -300,
      origin: 'https://portal.form.io',
      referrer: '',
      browserName: 'Netscape',
      userAgent: '<user agent value>',
      pathName: '/',
      onLine: true,
      headers: [Object]
    },
    state: 'submitted',
    form: '62a745944e836ccf1c0ba167',
    project: '61d21695ecb3f85c774e8f09',
    _fvid: 0
  },
  submission: {
    owner: '61c5e59add38c4e4a356acb0',
    deleted: null,
    roles: [],
    _id: '62e052a316f1ad4f786d4038',
    _vid: 0,
    _fvid: 0,
    state: 'submitted',
    data: { textField: 'Test value', number: 12345, submit: true },
    access: [],
    metadata: {
      timezone: 'America/Chicago',
      offset: -300,
      origin: 'https://portal.form.io',
      referrer: '',
      browserName: 'Netscape',
      userAgent: '<user agen value>',
      pathName: '/',
      onLine: true,
      headers: [Object]
    },
    form: '62a745944e836ccf1c0ba167',
    project: '61d21695ecb3f85c774e8f09',
    externalIds: [],
    externalTokens: [],
    created: '2022-07-26T20:46:27.232Z',
    modified: '2022-07-26T20:46:27.233Z',
    __v: 0
  },
  params: { formId: '62a745944e836ccf1c0ba167' }
}
```


# Submissions

A Submission is a JSON object whose values were submitted to a form or resource. These can be thought of as “objects” within the system and operate very much like them. A typical submission JSON object looks like the following:

```javascript
{
    "_id": "123456789012345678901234",
    "data": {
        "firstName": "Sally",
        "lastName": "Thompson"
    },
    "metadata": {},
    "state": "submitted",
    "form": "123456789012345678901234",
    "project": "123456789012345678901234",
    "created": "2021-05-24T13:51:43.414Z",
    "modified": "2021-05-24T13:51:43.415Z",
    "owner": "123456789012345678901234",
    "roles": [],
    "access": []
}
```

These properties are described as follows:

| Property | Description                                                                                                                                  |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| \_id     | The MongoDB ID of the submission                                                                                                             |
| data     | The values of the form that were submitted.                                                                                                  |
| metadata | Additional metadata that is added to the submission, such as timezone information.                                                           |
| state    | The state of the submission. "draft" for draft submission, and "submitted" would mean it has been submitted.                                 |
| form     | The Form ID for this submission.                                                                                                             |
| project  | The Project ID where this submission resides.                                                                                                |
| created  | The date this submission was created.                                                                                                        |
| modified | The date this submission was modified.                                                                                                       |
| owner    | The ID of the "user" who created this submission.                                                                                            |
| roles    | If this submission is used as a "user" submission, these are the roles that are added to that user.                                          |
| access   | Access configurations for this submission. This is used when field based resource access is used to establish permissions to the submission. |

## Accessing Submissions

All form submissions can be accessed through the Developer Portal UI, programmatically through the API, or exported in different formats. Since submissions are JSON objects, they are easy to use across the entire application environment and elsewhere within the Form.io Platform. The standard nature of JSON makes submissions easily interoperable with many other data management tools and processes.

Refer to the [Accessing Submissions](/form-building/submissions/accessing-submissions) subtopic for greater detail.

## Importing Submission Data

While all submissions against forms will generate submission objects in that project, many customers may need to migrate data from one project to another, or import data from other systems or elsewhere in their environment.

Refer to the [Importing Submissions](/form-building/submissions/importing-submissions) subtopic for greater detail.

## Submission Revisions

**Submission Revisions** are a feature that provide audit logging of who has updated a submission, when a change was made, and any notes associated with the update. Additionally, **Submission Revisions** can be used to revert to previous versions while safeguarding all submission data. The Submission Revision feature was introduced in **API Server Version** **7.4.0**. Please note: Submission Revisions are not needed to edit submissions, it is an audit logging capability to track changes that were made.\
\
Please note: Submission Revisions are not needed to edit submissions, it is an audit logging capability to track changes that were made.

{% hint style="info" %}
This feature is included in the [Security and Compliance](/dev/the-security-module) package. Follow the link or contact <sales@form.io> for more details.
{% endhint %}

### Enable Submission Revisions <a href="#enable-form-versioning" id="enable-form-versioning"></a>

To get started, create or edit a Form or Resource.

In the **Revisions** section, in the **Submission Revisions** block, expand the select dropdown menu and select **Enable** option.

<figure><img src="/files/90bR26LMgfwCy2c1wqKm" alt=""><figcaption></figcaption></figure>

After adding these settings on the tab, each time you make a change to the submission, a new version of it will be created.

### View and Updating Submission Revisions

After configuring Submission Revisions, the settings, the **Edit** submission tab has the following form:

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

Use the **Revision Note** field to add a comment to a submission revision.

{% hint style="info" %}
A Submission Revision will not be created unless a change is made to the submission
{% endhint %}

Click the **Revision** tab to review all revisions for the submission.

<figure><img src="/files/EOW5JOqVcbqUmn35gcRE" alt=""><figcaption><p>Revision list for the submission</p></figcaption></figure>

Click the **View** button to review a specific revision.

Click the **Restore** button to revert the submission back to that specific version.

### Submission Revision Log <a href="#enable-form-versioning" id="enable-form-versioning"></a>

Generate a PDF output report of all Submission Revision changes made to the submission. To activate the Submission Revision Log, access your **Form Settings**.

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

Scroll down to the **PDF Settings** block and check **Show Change Log** option.

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

After this configuration is set, downloading a PDF of the submission pdf file will contain information such as the Revision ID, the User who updated the submission, data and time of the update, submission revision note related to the change, and a list of all revision changes made.

![Submission Revision PDF output log](/files/d1cHUis770lIYtYFlDhc)

## **Submission Collection**

Enables the storage of submission data within a separate [**database collection**](https://www.mongodb.com/docs/manual/core/databases-and-collections/#collections). These collections can be configured on a per-form basis.

{% hint style="info" %}
This feature is included in the [**Security and Compliance**](/dev/the-security-module) package. Follow the link or contact <sales@form.io> for more details
{% endhint %}

For read-heavy applications, a database index can be set on fields that are used often for application performance improvements.

Compliance requirements - Ensure data separation between collections.

**Enable Submission Collection**

To configure this feature, navigate to the Form or Resource you want to configure the Collection for and click the form settings button.

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

If you have an active Security and Compliance package, you will see the Submission Collection field enabled within your settings. Set the collection folder from your database and save your settings.

<figure><img src="/files/74z4mwPNRBcdSpWWDWrD" alt=""><figcaption><p>Submission Collection field in Form Settings</p></figcaption></figure>

Once active, all data submitted with this Form or Resource will save in the specified database collection.


# Accessing Submissions

There are generally two ways of accessing submissions:

1. Through the UI.
2. Through the API.

There are a number of interfaces that can be used to examine and export the submission data of a form. These are as follows.

## Accessing Submissions though the Data tab

Form submissions can be seen by clicking on the **Data** tab on a form within the Developer Portal:

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

This is best treated as a form administrator or form developer review tool. Submissions containing many fields are not easy to review in the table view, and some field types may not display all the data captured in this view.

The Submissions page provides an administrative overview of submissions to a form.

The Data tab's table only displays the fields that had “Table view” selected on them. To add or remove fields from this display, edit the field on the Form Edit page and uncheck “Table View.”

![Table View configuration found within the Display tab of the component settings](/files/uedl77KE5bs1voOtr4Xn)

Developer Portal users with sufficient permissions can view, edit and delete individual submissions to forms. Use the icons on the right to perform these actions.

## Exporting Submission Data

Use the two **Export** buttons at the top of the submissions list to export all of the submission data for the given form. These operations are streamlined directly from the database and will work on very large datasets without having to write everything out to the server before starting the download.

### **Export JSON**

JSON (Javascript Object Notation) is a way of representing data in a standardized way for javascript applications. Many other programming languages and tools can read JSON as well. Since data in Form.io is stored in JSON format, this will be the truest form of the data.

### **Export CSV**

CSV (Comma Separated Values) is another way of representing data. Data is squashed down to rows of values with commas between them. This may not work well for complex data structures as it is essentially a flat file. CSV files can be opened by spreadsheet applications like Excel.

## Accessing Submissions through the API

Submissions data can be easily accessed via the API. This allows submission data to be used elsewhere within the application, other places in the Form.io platform, or by entirely separate services within the customer environment.

The API provides many powerful and flexible ways to submit, collect, migrate, modify, or otherwise handle submission data.

For more detailed information, refer to the Form.io API reference:

{% embed url="<https://apidocs.form.io/#9fe90026-dd4b-a344-62e9-c7a67f0ebbb7>" %}

### Temporary Tokens

To maintain security, API calls require some kind of authentication. This can take the form of passing JWT tokens in the header, invoking admin keys configured in the deployed environment, or generating temporary tokens.

**Temporary tokens** are short-lived and usually scoped to a limited purpose. Users will typically generate the token and then use it to make the desired call.

#### Example: Using Temporary Tokens to Download Submission as PDF

To understand this, consider a user who wants to download a PDF of an individual submission. To do so, they would use the following two calls:

1. GET a temporary download token:<br>

   ```html
   GET {{projectUrl}}/token
   ```

Headers:

<table><thead><tr><th width="113.390625" align="center">Key</th><th width="675.73828125" align="center">Value</th></tr></thead><tbody><tr><td align="center">x-allow</td><td align="center">GET:/project/{{projectId}}/form/{{formID}}/submission/{{submissionID}}/download</td></tr><tr><td align="center">x-expire</td><td align="center">3600</td></tr><tr><td align="center">x-jwt-token</td><td align="center">&#x3C;Retrieved through the browser's Developer Tools > Storage > Local Store > formioToken></td></tr></tbody></table>

{% hint style="info" %}
Note how the **x-allow** key limits the scope of the token to a specific project, form, and submission. Using a token issued with this scope on a different endpoint will result in an error.
{% endhint %}

2. GET a download of the PDF:

```
GET {{projectUrl}}/form/{{formID}}/submission/{{submissionID}}/download?token={{tempToken}}
```

Where {{tempToken}} is the key (**not** the "token") contained in the body of the reply to the first call.

#### Walkthrough:

Consider a Developer Portal at <http://localhost:3000>.

From the Developer Portal Home, navigating to **Doc Team Project > Doc Test Form > Data** shows the Submission the user wishes to download as a PDF.

Selecting the Submission and clicking **View** shows the submission at <http://localhost:3000/#/project/2468abc/form/1369def/submission/7777ghi>

The **Live Stage** link shows as <http://localhost:3000/qwertasdf>

<figure><img src="/files/8ilbW5tL2yltiIg5n0tP" alt="" width="375"><figcaption></figcaption></figure>

Observe the following:

* The **projectURL** is *<http://localhost:3000/qwertasdf>*
* The **projectID** is *2468abc*
* The **formID** is *1369def*
* The **submissionID** is *7777ghi*

Suppose the user found via **Tools > Developer Tools** **> Storaage > Local Storage** that

* The **formioToken** is *1z1y2x35w81v32u1* (in practice it will be significantly longer)

The user would use their preferred API tool (such as Postman) to send the following request:

```html
GET http://localhost:3000/qwertasdf/token
```

<table><thead><tr><th width="109.73046875" align="center">Key</th><th align="center">Value</th></tr></thead><tbody><tr><td align="center">x-allow</td><td align="center">GET:/project/<em>2468abc</em>/form/<em>1369def</em>/submission/<em>7777ghi</em>/download</td></tr><tr><td align="center">x-expire</td><td align="center">3600</td></tr><tr><td align="center">x-jwt-token</td><td align="center"><em>1z1y2x35w81v32u1</em></td></tr></tbody></table>

{% hint style="info" %}
Note how the **x-allow** key's values set the scope of the temporary token the user will receive, attaching it to a specific project, form, and submission.
{% endhint %}

When this is successful, the body of the return will contain both the **x-jwt-token** submitted by the user as well as a **"key"** required to issue subsequent calls:

<figure><img src="/files/QjB0GYgEFoTUyCy501dB" alt=""><figcaption><p>A Postman request for a temporary token.</p></figcaption></figure>

The user would record the **key** value (*GZZFpJsyYQTWoKCdPJOyYfKRZj2GBW*) for use in the second request.

Next the user would make the following request:

<pre><code><strong>GET http://localhost:3000/project/2468abc/form/1369def/submission/7777ghi/download?token=1z1y2x35w81v32u1
</strong></code></pre>

Note that the endpoint mirrors the scope set in the previous requests x-allow value.

For this call, the **key** from the previous call is supplied as the parameter by appending\
`?token=GZZFpJsyYQTWoKCdPJOyYfKRZj2GBW` to the request.

This will return the PDF of the submission, accessed with the temporary token.

<figure><img src="/files/63zuq2FZv6M5rPE9YP3R" alt=""><figcaption><p>The returned PDF</p></figcaption></figure>

The same process is used for a variety of calls requiring temporary tokens.

{% hint style="warning" %}
**Troubleshooting**: The most common errors when attempting to use a temporary token to make an API request are **400** and **440**, which may both be reported as "Expired token."\
To resolve these, first ensure the jwt-token used to generate the temporary token is still valid and entered in its entirety.\
Next, ensure the that the scope of the temporary token matches that required of the intended request. A malformed **x-allow** header may still return a temporary token, but if the requested scope is mis-matched to the second request, it will appear expired.\
Finally, ensure the download request uses the **key** returned when requesting the temporary token.
{% endhint %}


# Importing Submissions

## Importing Submission Data

Whether you're migrating data between projects or importing data from an external database, the **Import CSV** button allows you to select a CSV file containing data from your local machine and import that data into the given Form or Resource.

{% hint style="warning" %}
When importing submissions through a CSV, each imported submission may trigger any configured [actions](/form-building/actions) as if that submission derived from a form user. When importing a significant number of submissions, consider temporarily disabling actions such as email notifications.
{% endhint %}

### **Configuring CSV Files**

In order to import data, a properly configured CSV File is required for the import to succeed. The CSV column headers need to map directly to the fields on the form you wish to import data to. Ensure that your column headers match the **Property Name** of your fields before importing the file.

Use the CSV rows to add different submission entries within the file.

<figure><img src="/files/644PL5xqR4yKpavONLR6" alt=""><figcaption></figcaption></figure>

### Importing File

When your CSV file is ready, click the **Import CSV** button within the data tab and select the file.

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

{% hint style="warning" %}
Selecting the **Replace all submissions** setting will replace all existing submission entries with the row data inside the CSV file
{% endhint %}

Once the import is complete, the Submission View table will reflect the CSV file entries.

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


# Form.io Developer Guide

The Form.io Developer Guide provides technical content related to integrating Forms into an application, extending and customizing the Form.io platform, and integrating outsider services such as authentication into the Form.io.

### Popular Topics

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>Form Embedding</h4></td><td>Embedding the Form Renderer in an application.</td><td></td><td></td><td><a href="/pages/p49Uxssf6hv4tGgilmCL">/pages/p49Uxssf6hv4tGgilmCL</a></td></tr><tr><td><h4>Form Renderer</h4></td><td>Understanding how Forms are rendered in Form.io</td><td></td><td></td><td><a href="/pages/PxQDD6knBNll5OJpd87f">/pages/PxQDD6knBNll5OJpd87f</a></td></tr><tr><td><h4>Integrations</h4></td><td>Integrating other services with the Form.io platform.</td><td></td><td></td><td><a href="/pages/1x02GSFIvD4uxBXfxnPg">/pages/1x02GSFIvD4uxBXfxnPg</a></td></tr></tbody></table>


# AI and Form.io

Using AI, LLMs, and machine learning alongside the Form.io Platform.

Form.io serves as the data standardization layer for enterprises in regulated industries. AI may chang who builds applications, but does not change the need for secure and reliable infrastructure that supports such applications.

Form.io offers two products for working with AI — the Agentic Coding Toolset for the build moment, and the Universal Agent Gateway for the runtime moment.

## Agentic Coding Toolset

The Agentic Coding Toolset is a Claude Code plugin, an MCP server, and a skill library that brings Form.io into the AI coding environment. It allows an AI agent to build applications on Form.io. Anything from planning data models, generating forms, configuring access controls, and scaffolding front-ends, it works at the point of development or buildout.

[Learn more about the Agentic Coding Toolset.](#agentic-coding-toolset)

## Universal Agent Gateway (UAG)

The Universal Agent Gateway is a runtime governance layer that lets AI agents interact with deployed Form.io applications through the Model Context Protocol. It enables AI agents in production to read, submit, and update form data inside an enterprise system. UAG operates at runtime or in production.

[Learn more about UAG.](#universal-agent-gateway-uag)


# Agentic Coding Toolset

Using AI in the development of Form.io applications.

The Agentic Coding Toolset brings Form.io into an AI coding environment. The Agentic Coding Toolset is what an AI agent uses while writing code. It can plan data models, generate forms, configure access controls, and scaffold front ends on the Form.io platform.

## What's in the toolset?

The toolset is delivered as a single Claude Code plugin (@formio/ai) that bundles three components. It includes the following components:

* **Claude Code plugin (@formio/ai)** - Registers the MCP server and skills library with Claude Code. Can be installed with a single command.
* **MCP Server (@formio/mcp)** - Exposes Form.io operations (form\_, role\_, action\_, project\_) as MCP tools the agent can call. Works with any MCP-aware client such as Claude, Visual Studio Copilot, or Bolt.
* **Skills Library** - Enables covering app orchestration, resource planning, framework scaffolding, form authoring, action configuration, and the full Form.io REST surface.

## How the toolset works

When an agent receives instructions on what to build, it reviews the relevant skills to understand Form.io's primitives, then calls MCP tools to make changes in the Form.io project. The available skills are used to shape the pattern of the solution, while the MCP tools give it access to the functions necessary to accomplish that.

Every app the agent builds inherits the model, the governance, RBAC, and the audit trail by default. Approval gates run at every write — the agent doesn't make changes without your review.

### What can the toolset do?

The toolset handles solutions of varying scale and complexity — building from scratch, extending an existing app, modifying access controls, planning a data model, and operational queries against a live project.

Three examples:

#### Build a complete app from one prompt:

*"Build me a CRM where sales reps only see accounts owned by the teams they belong to."*

The agent plans the data model, imports it into Form.io, and scaffolds an Angular front-end wired to the project. At the end, it delivers a running application.

#### Tighten access controls on an existing resource.

*"Currently anyone authenticated can read every Account. Lock it down so reps only see Accounts owned by their Team."*

The agent reads the resource, modifies the access rules, and ensures the supporting role assignments are in place. The diff is provided for review before anything ships.

#### Plan a data model from plain language.

*"Plan the resource structure for a multi-tenant booking system where customers book services from providers, providers belong to one or more locations, and admins manage everything."*

The agent runs a structured interview, produces an ER diagram and access matrix for review, and emits a project template ready to import.

#### Additional Examples

See more examples in the [Form.io Agentic Coding Toolkit GitHub repo](https://github.com/formio/ai).

## Getting started

The toolset installs as a Claude Code plugin:

1. From inside Claude Code, run

```
/plugin install formio-ai@formio
```

2. A prompt will request **FORMIO\_BASE\_URL** and **FORMIO\_PROJECT\_URL.**
3. When installation is complete, it may be necessary to restart the terminal session or desktop application.

The agent can now respond to natural langauge requests, documents, or images to begin working on a project.

For full setup instructions, including the standalone MCP server for use with Claude Desktop, VS Copilot, or other MCP-aware clients, see the [Form.io Agentic Coding Toolkit GitHub repo](https://github.com/formio/ai).


# UAG

The **Universal Agent Gateway** (UAG) introduces the power of Form.io forms to AI agents.

The Form.io UAG uses the [**Model Context Protocol (MCP)**](https://modelcontextprotocol.io/docs/getting-started/intro) to enable Form.io functionality through an AI agent workflow. By providing AI agents with the **dynamic context** of how to use Form.io JSON forms, the UAG allows a user to interact with any aspect of their enterprise system served by the Form.io Platform directly through their AI agent.

## Model Context Protocol (MCP)

The Model Context Protocol (MCP) is an open-source standard for connecting AI applications to external systems.

The MCP essentially puts an AI agent's hands on the controls of an external system. In the case of Form.io, the MCP describes a discrete set of tools the AI agent can use to interact with forms, fields, and submissions. While some tools are delivered off-the-shelf, this functionality can be extended, modified, or refined through custom built modules.

### Dynamic Context

What does it mean to say MCP provides a dynamic context for how to use these tools?

The power of AI agents is their ability to parse natural language and infer a user's intent rather than take rote input like a command line. The dynamic context delivered by MCP gives the AI agent guidance on how to correlate the user's prompt to the tools and data avai. When the AI agent receives a prompt, it uses this dynamic context to determine what tool it should use, what elements of the prompt are inputs to that tool, and what additional input might be necessary.

## What is the Form.io UAG?

The UAG is the package that contains everything sitting between the Form.io Platform and the AI agent. It contains the stock MCP server, the authorization infrastructure, and any custom tools or modules that extend the functionality.

By equipping an AI agent with Form.io capabilities, the UAG brings the AI agent much deeper into the broader application ecosystem.\
Form.io's drag-and-drop Form Builder simultaneously defines the look of the form and the structure of the data. This makes it easy to use data collected through Form.io forms elsewhere in an application, or as an input to other enterprise systems.

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

### Pre-Defined MCP Tools

These tools are available in the standard MCP. These tools represent what an AI agent is capable of doing within a project.

<table data-full-width="true"><thead><tr><th width="234.765625">Tool Name</th><th>Description</th></tr></thead><tbody><tr><td>get_forms</td><td>Provides the AI agent with a list of available forms.<br>It will only return forms that have been tagged <code>uag</code>.</td></tr><tr><td>get_form_fields</td><td>When the AI agent infers the user intends to use a specific form, this tool provides the agent with a high level overview of all the fields needed (along with the field data path) to submit that form.</td></tr><tr><td>get_field_info</td><td>Once the fields have been determined using <code>get_form_fields</code>, this tool provides specific information about the requested fields, such as validation, conditionals, input formats, etc.<br>This tool instructs the AI agent on how to format and structure the data that is sent to the MCP server.</td></tr><tr><td>collect_field_data</td><td>Provides the AI agent with a mechanism to dynamically collect the required information from the user. It can parse the user's input into multiple fields at once, and will identify additional inputs from the user if needed.<br>This tool supports complex and structured data collection and is compatible with nested or multi-value fields like nested forms, data grids, etc.</td></tr><tr><td>confirm_form_submission</td><td>When the AI agent is ready to submit a form, this tool allows it to confirm all the information it has collected before a submission has been made to the form.</td></tr><tr><td>submit_completed_form</td><td>Provides the AI agent with the ability to submit all of the data collected from the user to create the form submission.</td></tr><tr><td>find_submissions</td><td>Enables the agent to parse a user's natural language request into a query for a submission, or a specific field of a particular submission.</td></tr><tr><td>submission_update</td><td>Provides the AI agent with the ability to update an existing submission, either by supplying unfilled fields or updating existing ones if allowed. Provides the AI agent with the context of the existing field values, allowing inline changes or edits.</td></tr></tbody></table>

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


# Connecting an AI Agent to UAG

## Claude Desktop

Coming soon.


# Deploying UAG

Creating a running instance of UAG.

The following sections describe the process of creating a running instance of UAG and connecting it to a Form.io Enterprise deployment.

For documentation on deploying UAG and connecting it to a Form.io Open Source, refer to the documentation on GitHub:

{% embed url="<https://github.com/formio/uag/>" %}

## Prerequisites

The following instructions assume that Form.io Enterprise has already been deployed.\
If there is no currently deployed instance of Form.io, refer to the appropriate deployment guide:

* [Local Deployment Guide](https://app.gitbook.com/s/KgNM52jrdfkHgHDfKCH9/local-deployment/readme) - Deploy a Form.io Enterprise container on a local machine.
* [AWS Deployment](https://app.gitbook.com/s/KgNM52jrdfkHgHDfKCH9/cloud-deployment/aws-deployment/readme)
* [Azure Deployment](https://app.gitbook.com/s/KgNM52jrdfkHgHDfKCH9/cloud-deployment/azure-deployment/readme)
* [Google Cloud Platform Deployment](https://app.gitbook.com/s/KgNM52jrdfkHgHDfKCH9/cloud-deployment/gcp-deployment/readme)

### Preparing a Project

Deploying a UAG container requires an existing project. Remember that the [project context ](/admin/projects/what-is-a-project)of Form.io means the AI agent will not be able to access forms or resources outside of this project.

Before proceeding:

1. Within the Form.io Developer Portal, open the **project** the UAG will connect to.\
   Create a project if one does not already exist.
2. Note the **Project URL** at the top of the page.\
   This will be `PROJECT`environment variable required later.
3. Click **Forms** from the left-hand menu of the Developer Portal, open the **User Login Form.**
4. Click **Embed** from the top menu bar.\
   Record the embed URL, this will be the `LOGIN_FORM` environment variable.
5. Open the project **Settings** page from the left-hand menu.
6. Click **API Settings** on the left side of the Settings panel.
7. Under the **API Keys** tab, click **+ Create Another.**
8. Give the key a descriptive name and click **Save**.\
   Record the string of characters. This will be the `PROJECT_KEY` environment variable.

### Tag Forms and Resources

UAG will only have access to forms and resources that are tagged `UAG`. Open each form or resource that should be available to AI agents and apply the necessary tag:

1. Open the project UAG will connect to in the Developer Portal and open **Forms** on the left-hand menu.
2. Click the form name to open it, then click the **...** hotdog menu on the top bar.
3. From the dropdown, select **Form Settings**.
4. Scroll down to the **Form Tags** option and enter *UAG* in the text field.
5. Click **Save Settings** on the form settings page to complete the process.

Repeat these steps for all forms and resources that UAG needs access to.

## Create the UAG Container

While the UAG container does not necessarily need to exist on the same host as the rest of the Form.io Platform, most users will choose to do so.

Follow the steps for the appropriate provider to deploy the UAG.

### AWS

To begin, open the `docker-compose.yml` included in the multicontainer.zip created during the [initial deployment](/deploy/cloud-deployment/aws-deployment) of Form.io in a text editor.

Add the following to the `services` section:

```docker
  formio-uag:
    image: formio/uag:rc
    restart: always
    links:
      - api-server
    depends_on:
      - api-server
    environment:
      PORT: 3200
      DEBUG: formio.*
      PROJECT: CHANGEME
      PROJECT_KEY: CHANGEME
      JWT_SECRET: CHANGEME
      JWT_EXPIRE_TIME: 525600
      LOGIN_FORM: CHANGEME
      BASE_URL: CHANGEME
      UAG_LICENSE: CHANGEME
    ports:
      - "3200:3200"
```

{% hint style="info" %}
Some environment variables may not apply to all deployments.
{% endhint %}

On the Elastic Beanstalk Console, open the environment on which Form.io is deployed.

Update the **Environment Properties** table with any environment variable that were not already included.

A reference of of all potentially applicable properties is provided:

| Variable          | Description                                                                                                                                                                                              | Default | Example                                         |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------- |
| PROJECT           | The Project URL previously recorded.                                                                                                                                                                     |         | [http://localhost:3000](http://localhost:3000/) |
| PROJECT\_KEY      | The Project API Key previously recorded.                                                                                                                                                                 |         | CHANGEME                                        |
| UAG\_LICENSE      | <p>The license to run the UAG against a Form.io Enterprise Deployment.<br>Contact <a href="mailto:support@form.io"><support@form.io></a> to purchase a license or request a trial.</p>                   |         |                                                 |
| PORT              | The port to run the UAG server on.                                                                                                                                                                       | 3200    | 3200                                            |
| DEBUG             | Variable used to perform debug logs of server activity                                                                                                                                                   |         | formio.\*                                       |
| PORTAL\_SECRET    | Allows the UAG to connect to the Form.io Enterprise Portal.                                                                                                                                              |         | CHANGEME                                        |
| JWT\_SECRET       | A secret used to generate and validate JWT tokens generated through the authentication process of the UAG. This does not need to match the JWT\_SECRET of the Enterprise Server that it is connected to. |         | CHANGEME                                        |
| JWT\_EXPIRE\_TIME | The expiration for the jwt secret.                                                                                                                                                                       | 3600    | 3600                                            |
| MONGO             | Allows the UAG to connect directly to a MongoDB database without having to redirect the submissions to the Form.io Submission API.                                                                       |         |                                                 |
| MONGO\_CONFIG     | JSON configuration for the Node.js Mongo Driver.                                                                                                                                                         |         |                                                 |
| BASE\_URL         | The public URL that the UAG is hosted on. This allows for proper OIDC authentication and allows for the authentication callbacks to point to the correct url.                                            |         | [https://ai.onform.io](https://ai.onform.io/)   |
| LOGIN\_FORM       | The public URL to the Login Form JSON endpoint.                                                                                                                                                          |         | <https://mysite.com/project/user/login>         |
| CORS              | The CORS domain, or the JSON configuration to configure the "CORS" node.js module cross domain resource sharing.                                                                                         |         | *.*                                             |
| PROJECT\_TTL      | The number of seconds that the connected project is checked for any changes. Reducing the number would allow more immediate reflection of project changes within the UAG.                                | 900     | 15                                              |
| MAX\_BODY\_SIZE   | The maximum size for the JSON body to be when an AI Agent is communicating to the UAG. Use "kb", "mb" to denote kilobytes and megabytes respectively.                                                    | 100mb   | 200mb                                           |

After saving the modified `docker-compose.ym`l to `multicontainer.zip`, upload the new .zip and deploy it.

AWS should use the `docker compose up` command internally when launching the UAG container. This should leave any unmodified containers operational through the process.

## Azure

Coming Soon

### GCP

Coming Soon

### Local


# Application Development

Let's create an application using Form.io!

The most advanced way to use Form.io is to embed the Form.io renderer directly within any Web based application you are developing. The Form.io platform supports a large number of different application development frameworks such as the following.

| Framework        | Github URL                                                                                                 |
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
| Vanilla JS       | [**https://github.com/formio/formio.js**](https://github.com/formio/formio.js)                             |
| Angular          | [**https://github.com/formio/angular**](https://github.com/formio/angular)                                 |
| Angular Material | [**https://github.com/formio/angular-material-formio**](https://github.com/formio/angular-material-formio) |
| AngularJS        | [**https://github.com/formio/ngFormio**](https://github.com/formio/ngFormio)                               |
| React            | [**https://github.com/formio/react-formio**](https://github.com/formio/react-formio)                       |
| Vue              | [**https://github.com/formio/vue-formio**](https://github.com/formio/vue-formio)                           |
| Aurelia          | [**https://github.com/formio/aurelia-formio**](https://github.com/formio/aurelia-formio)                   |
| React Native     | [**https://github.com/formio/react-native-formio**](https://github.com/formio/react-native-formio)         |

Each one of these landing pages provides its own documentation on how to create new applications using these frameworks. For this tutorial, however, we will pick one (**Angular**) and demonstrate how an application can be created using this powerful platform. For this tutorial, we will build an application that demonstrates many of the different features of the Form.io platform; An **Event Registration Application** using the [**Angular framework**](https://angular.io).

Let's get started by Creating a new project.

## Create your Project

After you create a new account at <https://portal.form.io>, you will see a page that looks like the image below. The first thing we will do is to create a new Project, which we can do by clicking the **Angular** button, or by clicking on the **Create Project** button.

![](/files/wgAcE79dAjMdaUZ3pUi9)

Provide your project information like so, and then click **Create Project**

![](/files/ycP5a7s7R8T2vXAohBzL)

## Create Resources

An Event Registration application will need to store some “structured” objects called **Events**. These are called **Resources** in Form.io, so let's create a new **Event** by clicking on the following.

![](/files/4twHO2oso0aK5jKXLXcN)

We will then build our **Event** object using a form builder. We could also provide some field validations and such, but for now we will keep the form simple.

![](/files/52mxJxp5kIOlP7TdVo1c)

When you are done, click on **Create Resource.** This immediately demonstrates one of the differentiating features of Form.io, where Data Models and Resources can be constructed using a simple drag-and-drop form builder interface. We can even control who has access to create this Event within the Access section.

### Assigning Permissions

You now need to allow **Authenticated** users to read all events. We will also want them to be able to **create their own**, **update their own**, and **delete their own** events. To do this, click on **Access** section, and configure the settings as follows.

![](/files/MrkwPkuv2cX1IEGoCVoA)

The settings should automatically save when you add this role to these permissions.

## Event Registration Form

Now that we have an Event resource, we need a way for people to register to attend the Event. This is a great use case for a **Form** that provides “unstructured” data that references Resources.

Let’s create a new form by clicking on the **Forms** section and pressing **New Form**, and then selecting ***API Web Form***.

Here we will build a **Registration** form. The first field we will add to this form is a **Select** component field like so…

Once we add this, field, we will give it a label of **Event**.

![](/files/VhWB68kRqeCisjscQYFh)

We will then click on the **Data** tab, and then set the **Data Source** to **Resource**, and then select the **Event** Resource like so.

![](/files/527iG7tDLc5fDS3qC0X3)

Finally for the **Item Template**, we will provide the following code.

```
<span>{{ item.data.title }}</span>
```

Like the following shows.

![The Item Template for an Event resource select dropdown](/files/sN65isuVK4hjXr1MFfVX)

Next, we can press the **Save** button to add the field to our form. Now that we have an **Event** resource field, we can add other fields to the registration form like so…

![](/files/xZ4C1hH4X3tU2LAK4xyY)

We will now press the **Create Form** button to save our form. Now, let us configure the access permissions of this form.

### Access Permissions

We also need to ensure that **Authenticated** users can submit the Registration Form, so we will go to the **Access** section and configure the following.

![](/files/4UAHgdCXndBKVVue0rqb)

The permissions should automatically save when you set them.

We are now done setting up our Form.io Resources + Forms for our application, now let's build an app!

## Create an Application

To get started quickly in [**Angular**](https://angular.io/), we recommend using the [**Angular CLI**](https://cli.angular.io/) tool to create our application. We can do this by typing the following within your terminal.

```
npm install -g @angular/cli
ng new eventmanager --style=scss --routing=true --strict=false
```

This will now create a new application within the folder **eventmananger**, we can navigate into that folder by typing the following in the terminal.

```
cd eventmanager
```

We will now bring in all of our dependencies into the application by typing the following within the application folder.

```
npm install --save bootstrap@4 bootstrap-icons formiojs @angular/elements ngx-bootstrap --legacy-peer-deps;
npm install --save @formio/angular --tag=rc --legacy-peer-deps
```

Or if you are using yarn, you can instead run the following

<pre><code><strong>yarn add bootstrap@4 bootstrap-icons @formio/js @angular/elements ngx-bootstrap;
</strong><strong>yarn add @formio/angular@rc
</strong></code></pre>

We can now setup the styles for our application by editing the following file.

***src/styles.scss***

```
$bootstrap-icons-font-dir:'../node_modules/bootstrap-icons/font/fonts';
@import "bootstrap/scss/bootstrap.scss";
@import "bootstrap-icons/font/bootstrap-icons.scss";
```

We will now start our application by typing the following in the terminal.

```
ng serve
```

You should now be able to go to **<http://localhost:4200>** in your browser to see the default Angular page.

We can now create a home page, by typing the following in the terminal.

```
ng g component home
```

And then provide the following code in the following file.

***src/app/home/home.component.html***

```
<div class="jumbotron">
  <h3>Event Registration Application</h3>
  <p>This is an example home page for the Event Registration Application</p>
</div>
```

And then add the following to the routes.

***src/app/app-routing.module.ts***

```
...
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  {
    path: '',
    component: HomeComponent
  }
];

...
```

Next, we will need to make sure that our root component, which is called AppComponent is able to display the content at this route. To do this, we will need to add a **router-outlet** to the template of this component. You can do this by opening up the following file and changing it to only have the following content.

***src/app/app.component.html***

```
<div class="container pt-3">
  <router-outlet></router-outlet>
</div>
```

Now, when you refresh you should see your home component as follows.

![](/files/8LOYq51T8FbKq2DmLF6n)

## Application Configuration

Now that we have an application running, we will need create a configuration file so that we can tell the application which Form.io project we are pointed to.

To do this, we will create a new **config.ts** file as follows.

***src/app/config.ts***

```
export const AppConfig = {
  appUrl: 'https://forms.mysite.com/myproject',
  apiUrl: 'https://api.mysite.com'
};
```

You will need to make sure that you replace “yourproject” with the name of your Project URL which you can find at the following location within your Project page.

![](/files/7JdWN0mqC4m9LZmttMOT)

Next, we will need to register this AppConfig within the main module by adding the following to the **app.module.ts** file.

***src/app/app.module.ts***

```
...
...
import { AppConfig } from './config';
import { FormioAppConfig } from '@formio/angular';

@NgModule({
  ...
  providers: [
    {provide: FormioAppConfig, useValue: AppConfig},
  ],
  ...
})
export class AppModule { }
```

## User Authentication

Now that we have the configuration file in place, we can setup User Authentication.

[**Angular Auth Documentation**](https://github.com/formio/angular-formio/wiki/User-Authentication)

We accomplish this by first creating an Angular module that will contain the authentication routes.

```
ng g module auth
```

This will create a new folder within our application within the **src/app** folder, which we can then use to include all the necessary modules to bring in Authentication.

***src/app/auth/auth.module.ts***

```
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormioAuth, FormioAuthRoutes } from '@formio/angular/auth';


@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    FormioAuth,
    RouterModule.forChild(FormioAuthRoutes())
  ]
})
export class AuthModule { }
```

We must now register the Authentication module by lazy loading the module within the “auth” route. We can accomplish this within the following file.

***src/app/app-routing.module.ts***

```
const routes: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
    path: 'auth',
    loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
  }
];
```

Next, we just need to register the service providers with configurations within the **app.module.ts** file.

***src/app/app.module.ts***

```
...
import { AppConfig } from './config';
import { FormioAppConfig } from '@formio/angular';
import { FormioResources } from '@formio/angular/resource';
import { FormioAuthService, FormioAuthConfig } from '@formio/angular/auth';

@NgModule({
  ...
  providers: [
    {provide: FormioAppConfig, useValue: AppConfig},
    FormioResources,
    FormioAuthService,
    {provide: FormioAuthConfig, useValue: {
      login: {
        form: 'user/login'
      },
      register: {
        form: 'user/register'
      }
    }}
  ],
  ...
```

We should now add a header to our application so that we can login, and see our login state.

We can now add a header to our application by adding the **nav** HTML to our existing router-outlet code we created earlier within the **app.component.html** file. It should look like the following.

***src/app/app.component.html***

```
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container">
    <a class="navbar-brand" href="#"><img style="height: 2em;" src="https://portal.form.io/images/formio-logo.png" /></a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarsExample07" aria-controls="navbarsExample07" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarsExample07">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#"><i class="bi-house-fill"></i></a>
        </li>
      </ul>
      <ul class="nav navbar-nav ml-auto">
        <li class="nav-item" routerLinkActive="active" *ngIf="!auth.authenticated">
          <a class="nav-link" routerLink="auth">Login | Register</a>
        </li>
        <li class="nav-item" *ngIf="auth.authenticated">
          <a class="nav-link" routerLink="/" (click)="auth.logout()"><span class="glyphicon glyphicon-off"></span> Logout</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
<div class="container pt-3">
  <router-outlet></router-outlet>
</div>
```

Next, we will need to add some logic within the **AppComponent** class to handle the authentication workflow.

***src/app/app.component.ts***

```
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { FormioAuthService } from '@formio/angular/auth';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'eventmanager';
  constructor(
    public auth: FormioAuthService,
    private router: Router
  ) {
    this.auth.onLogin.subscribe(() => {
      this.router.navigate(['/']);
    });

    this.auth.onLogout.subscribe(() => {
      this.router.navigate(['/auth/login']);
    });

    this.auth.onRegister.subscribe(() => {
      this.router.navigate(['/']);
    });
  }
}
```

We should now see the following within our application with a working authentication and registration system.

## Application Resources

Now that you have a running application with authentication, we can now add the **Event** resource using the **FormioResource** module.

[Angular Resource Documentation](https://github.com/formio/angular-formio/wiki/Resource-Management)

```
ng g module event
```

We will then add the following to the following module file.

***src/app/event/event.module.ts***

```
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from '@formio/angular/resource';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    FormioResource,
    RouterModule.forChild(FormioResourceRoutes())
  ],
  providers: [
    FormioResourceService,
    {provide: FormioResourceConfig, useValue: {
      name: 'event',
      form: 'event'
    }}
  ]
})
export class EventModule { }

```

The next thing we will need to do is to register this event within the router.

***src/app/app-routing.module.ts***

```
const routes: Routes = [
  ...
  ...
  {
    path: 'event',
    loadChildren: () => import('./event/event.module').then(m => m.EventModule)
  }
];
```

Finally, you will add a link to the navigation bar to go to the Events section when you click it.

***src/app/app.component.html***

```
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container">
    <a class="navbar-brand" href="#"><img style="height: 2em;" src="https://portal.form.io/images/formio-logo.png" /></a>
    <ul class="nav navbar-nav mr-auto">
      ...
      <li class="nav-item" routerLinkActive="event" *ngIf="auth.authenticated">
        <a class="nav-link" routerLink="event"><i class="bi-calendar"></i> Events</a>
      </li>
    </ul>
    ...
  </div>
</nav>
...
```

You now have a complete Event management system!

![](https://help.form.io/assets/img/userguide/eventindex.png)

Let’s add our Registration form!

## Event Registration

We will now add the **Event Registration** form to the event. Since forms and resources are conceptually the same thing in Form.io, we can use a nested resource to attach forms to any resource within our application. We can start by adding a submodule within Angular.

```
ng g module event/register
```

We can now add the following to the created file.

***src/app/event/register/register.module.ts***

```
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from '@formio/angular/resource';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    FormioResource,
    RouterModule.forChild(FormioResourceRoutes())
  ],
  providers: [
    FormioResourceService,
    {provide: FormioResourceConfig, useValue: {
      name: 'registration',
      form: 'registration',
      parents: [
        'event',
        {
          field: 'user',
          resource: 'currentUser',
          filter: false
        }
      ]
    }}
  ]
})
export class RegisterModule { }

```

Notice that we added the **parents** construct to our **providers**. This tells the Form.io Angular Resource system that this is nested within the Event resource as well as should contain the currently logged in User assigned to the new records as well.

Next, we need to mount this nested resource within the Event resource. To do this, we add it to the children of the Event resource routes as follows.

***src/app/event/event.module.ts***

<pre><code>...
import { RouterModule, Routes } from '@angular/router';
...

<strong>const eventRoutes: Routes = FormioResourceRoutes();
</strong>eventRoutes[2].children.push({
  path: 'registrations',
  loadChildren: () => import('./register/register.module').then(m => m.RegisterModule)
});

@NgModule({
  declarations: [],
  imports: [
    ...
    RouterModule.forChild(eventRoutes)
  ],
  ...
})
export class EventModule { }
</code></pre>

We can now navigate to the following url to see the Forms for a specific event, as well as all the registrations within that Event.

```
http://localhost:4200/event/[EVENTID]/registrations
```

Next, we will need to change the Event resource view so that we can add the tab to the interface.

```
ng g component event/resource
```

We can now add the following the the event resource html.

***src/app/event/resource/resource.component.html***

```
<ul class="nav nav-tabs" style="margin-bottom: 10px;">
  <li class="nav-item"><a class="nav-link" routerLink="../"><i class="bi-chevron-left"></i></a></li>
  <li class="nav-item"><a class="nav-link" routerLink="view" routerLinkActive="active">View</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="registrations" routerLinkActive="active">Registrations</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="edit" routerLinkActive="active">Edit</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="delete" routerLinkActive="active"><span class="bi-trash"></span></a></li>
</ul>
<router-outlet></router-outlet>
```

Next, we will need to extend the **FormioResourceComponent**

***src/app/event/resource/resource.component.ts***

```
import { Component } from '@angular/core';
import { FormioResourceComponent } from '@formio/angular/resource';

@Component({
  selector: 'app-resource',
  templateUrl: './resource.component.html',
  styleUrls: ['./resource.component.scss']
})
export class ResourceComponent extends FormioResourceComponent {}
```

And finally, we can register this within the routes using the following.

***src/app/event/event.module.ts***

```
const eventRoutes: Routes = FormioResourceRoutes({
  resource: ResourceComponent
});
```

This should create the following interface, where we can now view all of the registrations within an Event.

![](https://help.form.io/assets/img/userguide/eventform.png)

Let’s now change the Event view page to add a **Register for this Event** button!

## Event View

To change the view of the Event, we can use the same method we did for the Resource component, but this time we will create one for the event view.

```
ng g component event/view
```

We can now modify the following template with the following.

***src/app/event/view/view\.component.html***

```
<div class="row">
  <div class="col col-sm-6">
    <div class="card">
      <div class="card-header bg-primary text-white">
        <h3 class="card-title">Event Information</h3>
      </div>
      <ul class="list-group list-group-flush">
        <li class="list-group-item"><strong>Title:</strong> {{ service.resource.data.title }}</li>
        <li class="list-group-item"><strong>Description:</strong> {{ service.resource.data.description }}</li>
        <li class="list-group-item"><strong>Date:</strong> {{ service.resource.data.date }}</li>
      </ul>
    </div>
  </div>
  <div class="col col-sm-6">
    <div class="card">
      <div class="card-header bg-success text-white">
        <h3 class="card-title">Event Registration</h3>
      </div>
      <div class="card-body">
        <a routerLink="../registrations/new" class="btn btn-primary">Register for this Event</a>
      </div>
    </div>
  </div>
</div>
```

Next, we need to extend the **FormioResourceView** as follows.

***src/app/event/view/view\.component.ts***

```
import { Component } from '@angular/core';
import { FormioResourceViewComponent } from '@formio/angular/resource';

@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrls: ['./view.component.scss']
})
export class ViewComponent extends FormioResourceViewComponent {}
```

And finally, we will register this with the **FormioResourceRoutes** as follows.

***src/app/event/event.module.ts***

```
const eventRoutes: Routes = FormioResourceRoutes({
  resource: ResourceComponent,
  view: ViewComponent
});
```

This produces the following result…

![](https://help.form.io/assets/img/userguide/eventview.png)

We now have a full working Event Management system, which even allows for other users to create an account and Register for this event. We hope that this walkthrough guide provides you a solid footing on building your next Progressive Web Application on Form.io!

If you would like to download the code behind this application, then go to [**Event Manager Github Page**](https://github.com/formio/eventmanager).


# Authentication and Authorization

A developers guide to the User Authentication and Authorization processes

## User Authentication

Form.io authentication provides a secure way to control access to forms and applications, ensuring that only authorized users can interact with sensitive data or perform specific actions on a Form. Form.io enables users to verify their identity using a variety of methods, including OAuth, SAML, LDAP, JWT tokens, or email/password. Here's how authentication typically functions:

1. **Authentication Method:** The first step in the authentication process is to decide what authentication method will be used for your client-side application. Form.io offers a multitude of different methods to authenticate users. Typically, Form.io users prefer to integrate their own authentication provider such as OAuth or SAML, to authenticate their client-side users. The Form.io project is then integrated with the selected authentication provider to facilitate the authentication process
   * [**OAuth**](/dev/authentication-and-authorization/oauth#openid-connect-oidc)
   * [**SAML**](/dev/authentication-and-authorization/saml#introduction)
   * [**LDAP**](/dev/authentication-and-authorization/ldap#setup)
   * [**Resource**](/dev/authentication-and-authorization/resource-based-authentication)
2. **Authentication Form Configuration:** Once the authentication method is set up, form builders can configure Login forms to support the authentication method. This configuration will vary depending on the chosen authentication method, but usually involves adding Actions or specially configured buttons to the authentication form to trigger the provider login request.
   * [**OAuth Login**](/dev/authentication-and-authorization/oauth#remote-authentication-sso)
   * [**SAML Login**](/dev/authentication-and-authorization/saml#authentication-configuration)
   * [**LDAP Login**](/dev/authentication-and-authorization/ldap#ldap-login-form)
   * [**Resource Login**](https://app.gitbook.com/s/DuAwTOTr6NFMpkfgwq9x/authentication-and-authorization/resource-based-authentication/readme#login-and-registration)
3. **Authentication Request:** When authentication is required, users are prompted to provide their credentials through the authentication form. Depending on the authentication method, this could involve entering user credentials for an OAuth or SAML provider, clicking a single sign-on (SSO) button, or entering an email address and password saved to a Form.io Resource or LDAP directory.
4. **Verification:** Once the credentials are submitted, Form.io verifies them against its authentication system. This will typically involve communicating with an external identity provider, checking the credentials against a user database saved to a Form.io Resource, or validating a JWT token.
5. **Authentication Success:** If the provided credentials are valid, Form.io grants access to the requested form or application by handing off a JWT access token. A Form.io Role is given to the user allowing them to interact with the form, submit data, or perform other actions as permitted by their authentication level and permissions. The role is distributed to the user based on the authentication method.
   1. [**OAuth Role Mapping**](https://help.form.io/dev/pages/0PLIsnMqHsFUSweDcF4S#mapping-oidc-roles-to-form.io-roles)
   2. [**SAML Role Mapping**](https://help.form.io/dev/pages/Uqe1teMnv42YElvynElx#form.io-integration)
   3. [**LDAP Role Mapping**](/dev/authentication-and-authorization/ldap#assign-roles)
   4. [**Resource Role Assignment**](/dev/authentication-and-authorization/resource-based-authentication#creating-a-login-form)
6. **Additional Security Measures:** Form.io offers additional security measures such as [**Two-Factor Auth**](/dev/authentication-and-authorization/resource-based-authentication/two-factor-authentication) (2FA) or [**reCAPTCHA**](/form-building/premium-components#recaptcha) verification to enhance security and prevent unauthorized access.

### Authentication Tokens

Form.io uses JSON Web Tokens (JWT) for all aspects of user authentication. When leveraging an external authentication method such as SAML or OAuth, the Form.io platform converts the provider tokens into equivalent JWT tokens. This token contains the JSON code with the User and Project ID. These IDs are then used to generate the user information saved to the user object which includes the Role. See the Authentication Flow detailed below for more information.

It is highly recommended to read how these tokens work to have a complete understanding of how the Authentication system within Form.io operates. Below are some resources to read regarding JWT.

* [**https://jwt.io/**](https://jwt.io/introduction)
* [**https://en.wikipedia.org/wiki/JSON\_Web\_Token**](https://en.wikipedia.org/wiki/JSON_Web_Token)

### Authentication Flow

The following diagram illustrates the flow for a Resource Based authentication method.

{% hint style="info" %}
Most customers choose integrate their application's existing authentication infrastructure, rather than use Resource-based authentication.
{% endhint %}

<img src="/files/U3qlob932fmXExRlFyTN" alt="Form.io JWT Authentication flow" width="375">

As this diagram illustrates, the mechanism that performs an authentication is achieved with the **Login Action** which is a form action that can be attached to any form within the Form.io platform. The series of steps that this Login action performs is as follows.

1. Inspects a POST body of the submission API call that was made against the authentication form.
2. Extract the "username" and "password" fields from the POST body. These fields are configured as part of the Login action configuration.
3. Perform a search against the underlying Resource to match a submission for the provided "username". The underlying resources are also configured as part of the Login action allowing you to authenticate against ANY resource.
4. Once a record has been found, it will then perform a one-way encrypted hash comparison between the password fields of that resource to ensure that the user who submitted the form has matched the password on that resource submission.
5. If the password hashes match, then the Login Action will then generate a JWT token of the resource submission object which will then become the User that is authenticated.
6. Assign that JWT token to the "x-jwt-token" response header which is then sent back to the client application.
7. The renderer will see that a "x-jwt-token" has been introduced and then save this token to the "formioToken" localStorage variable which will be used as the persistent authentication.

This JWT token is then used in every request made to the Form.io platform, which will serve as the authentication context for any request made into Form.io. If you wish to view the JWT token for any application that you are using connected to Form.io, you can navigate to the Local Storage of your browser and take a look at the `formioToken` localStorage variable like the following shows.

![](/files/okyd3BDBeytWeAe540Db)

The JWT token can also be read as raw JSON by copying the value of the JWT Token and then taking it to <https://jwt.io> to view the contents like the following illustrates.

![](/files/9G7JwS1sbXrjP04rac3h)

This JWT token forms the basis behind all authentication within Form.io. Even when other authentication providers are utilized such as SAML, Oauth, and LDAP, the goal of those actions is to exchange the tokens of those systems into a JWT token which is then used by the Form.io platform to establish authentication of an end user.

## User Authorization

User authorization occurs after the authentication process has been completed. Form and Application authorization access is determined by the user's role, which is assigned to a user after authentication. These Roles are linked to specific Permissions configured within the Forms of your Project. Permissions grant the User the ability to interact with forms, submit data, or perform other actions within both the forms and application. Here's how authorization typically works after the [**User Authentication**](#user-authentication) process is complete.

{% hint style="info" %}
Before you read this section, we highly recommend you read the [**Roles and Permissions**](/admin/roles-and-permissions) documentation to become familiar with the mechanics of how Users, Roles, and Permissions are handled within Form.io.
{% endhint %}

1. **Access Roles:** After successfully authenticating, Form.io grants the user access to the requested application by handing off a JWT authentication token. During this process, the user is assigned a Form.io [**Role**](/admin/roles-and-permissions#roles) which is an array of MongoDB IDs saved to the User object. These Roles are created and managed within the Form.io project. When authentication methods like OAuth or SAML are utilized, the authentication provider Role is mapped to a Form.io role. A typical user object within Form.io may look like the following. Take note of the Role ID in line 6.

<pre class="language-java" data-line-numbers><code class="lang-java"><strong>{
</strong><strong>  "_id": "661ffe3b2adabc01222babcd",
</strong><strong>  "form": "6347275deaed4f145892abcd",
</strong><strong>  "owner": "5bf5a5aa46322444b9f1abcd",
</strong><strong>  "roles": [
</strong><strong>    "6347275deaed4fe4ab926673"
</strong><strong>  ],
</strong><strong>  "access": [],
</strong><strong>    "login": {
</strong><strong>      "attempts": 0,
</strong><strong>      "last": 1713372778481
</strong><strong>    }
</strong><strong>  },
</strong><strong>  "data": {
</strong><strong>    "email": "joe@example.com"
</strong><strong>  },
</strong><strong>  "_fvid": 1,
</strong><strong>  "project": "6347275deaed4fff5592asbcd",
</strong><strong>  "state": "submitted",
</strong><strong>  "externalIds": [],
</strong><strong>  "created": "2024-04-17T16:52:11.998Z",
</strong><strong>  "modified": "2024-04-17T16:52:11.998Z",
</strong><strong>  "isAdmin": false,
</strong><strong>  "onlyPrimaryWriteAccess": false
</strong><strong>}
</strong></code></pre>

2. **Access Permissions:** The user-assigned Role is mapped to various [**Permissions**](/admin/roles-and-permissions#permissions) configured within the Form.io project. These permissions dictate the operations (Create, Read, Update, Delete, and Index) that can be performed by the authenticated user on forms and their associated submission data.

## Session Management

The Form.io platform ensures that every authentication within the platform is associated with a current "session". A Session is a mechanism to connect authenticated requests made by the same JWT token and ensures that "sessions" can be invalidated once a login occurs. This works by adding a Session ID to each JWT token provided to a user. This can be seen by copying your JWT Token from your localStorage (usually found within the **formioToken** variable) into jwt.io, which will give you the following.

```javascript
{
  "user": {
    "_id": "5e5411ba1e29ee1aab5031d9"
  },
  "iss": "https://api.mysite.com:3000",
  "sub": "5e5411ba1e29ee1aab5031d9",
  "jti": "5fffbb5646d76c292a7b5df1",
  "iat": 1610595158,
  "exp": 1610609558
}
```

The `jti` property is the current user Session ID and will change if the user logs out and then logs in again.

Once a user logs out of their account, by hitting the logout API, the current session will become invalid, and all outstanding JWT tokens that use that session ID will no longer be able to be used. The user must first login again, which will re-establish a new session, and then that JWT token can be utilized to make API calls into the Form.io platform.

The Session Management system is used as an added security measure to enforce that JWT tokens cannot be used again once a user has logged out of their account. This also protects the situation where if any user is using multiple devices and logs out of one device, their session will also be logged out of all other devices.

## Custom JWT Authentication

Any Deployed Enterprise customer can take advantage of this to establish their own custom authentication mechanisms by forging their own JWT tokens for their users.

There are many cases where Form.io needs to be tightly integrated into an existing platform with authentication mechanisms already established.

For these cases, Form.io can be utilized within deployed environments using JWT tokens that can be used as SSO into the Form.io platform. This does NOT require any user accounts within Form.io, but rather creates a way to pass along a dynamically generated JWT token claiming certain roles configured within the project.

Here is how it works.

* To get started, you will need to deploy your own on-premise deployment into your environment and ensure you set the `JWT_SECRET` of that deployment to a secret only you know.\
  Please see [**Docker Deployments**](https://help.form.io/deploy/) for more information.
* You will now need to create **Roles** within your Form.io project that you would like to use to control the access to certain Form.io operations. You can then assign those roles to the **Permissions** of the forms within the **Access** section of those forms. Please take note of the ID’s of these roles that were created since they will be used when generating the SSO tokens.
* Now that you have some Roles created, you will then need to generate a special JWT token within your own backend platform, or within an authentication proxy using something like AWS Lambda. The payload for this token needs to be as follows.

```javascript
{
  external: true,
  form: {
    _id: 'USER_RESOURCE_FORM_ID'
  },
  project: {
    _id: 'PROJECT_ID'
  }
  user: {
    _id: 'external',
    data: {
      name: 'joe'
    }
    roles: [
      'ROLE_ID_1',
      'ROLE_ID_2'
    ]
  }
}
```

You will then make the following replacements.

* **USER\_RESOURCE\_FORM\_ID** - This is the ID of the form/resource that would normally contain user records. NOTE: You do not need to provide a user record ID, but just the form ID.
* **PROJECT\_ID** - This is the Form.io project ID
* **ROLE\_ID\_1**, **ROLE\_ID\_2**, … - These are the ID’s of the roles you would like this token to have when authenticating.

This token can be generated using a number of ways and should be generated within your own backend server or hosted lambda function. Since you know the JWT secret of the Docker deployment, you can generate valid tokens such as the following code.

```javascript
/**
 * This code does require our Docker deployment where the "JWT_SECRET" would be the
 * same secret of the environment variable when the docker is spun up.
 */
var jwt = require('jsonwebtoken');
var token = jwt.sign({
  external: true,
  form: {
    _id: '59795d259be16e3ee58fddaa',
  },
  project: {
    _id: '59795d259be16e3ee58fdda6'
  }
  user: {
    _id: 'external',
    data: {
      name: 'joe'
    }
    roles: [
      '59795d259be16e3ee58fdda7'
    ]
  }
}, 'JWT_SECRET');
    
// We now have a token!
console.log(token);
```

This example uses Node.js and the [JSON Web Token](https://github.com/auth0/node-jsonwebtoken) library, but this could be done within any backend server language. You will also need to make sure to replace JWT\_TOKEN string with the password string you used for JWT\_TOKEN when you deployed the server via. Docker.

* Now that you have a token that is generated from the server, you will then send that to the client application when you serve the application. You can then place the following code in your Template to establish a SSO integration into Form.io.

```http
<script type="text/javascript">
localStorage.setItem('formioToken', 'FORMIO_TOKEN');
</script>
```

Here you would just replace the FORMIO\_TOKEN with the actual token generated from the server.

* Now that you have a token added to localStorage using the special token `formioToken`, this will be used for all communication to the Form.io API platform and authenticate as the Roles provided in the token!


# Email Authentication

In addition to providing full authentication capabilities, **Form.io** also provides a very robust method for Automatic Logins via Email. There are many use cases where Email Login is utilized including, but not limited to…

* Email Registrations (where they must click on a link in their email to register)
* Email Reset Password

{% hint style="info" %}
[**Click Here** ](/how/sso-email-token)for a walkthrough on how to integrate an SSO Email Token to authenticate your application user base using Form.io.
{% endhint %}

To make this happen, there is a special token that can be added to the message of your email action and templates. This token will generate a special JWT token to log in the person who the email was addressed to. This token is defined as follows.

```
  [[token(data.email=user)]]
```

Which is defined as follows…

```
  [[token(LOOKUP_FIELD=LOOKUP_RESOURCE)]]
```

* **LOOKUP\_FIELD** - This is the field that is used to search for the record we wish to login. This works by taking the value provided in the Email To: Address and searching the resource with that value as that field.
* **LOOKUP\_RESOURCE** - This is the resource to lookup when establishing the token.

***Important Note*** - This will ONLY create a token if the persons email address that is being sent the email is found within the resource.

For example, lets say you have a Resource as ***Customer*** and a field within that resource called ***Email*** you wish to create a token for. Now lets say you wish to send an email to one of your customers to complete their registration via email. This may look like the following.

```
  To:      john@example.com
  From:    no-reply@form.io
  Subject: Register Now
  Message: Click here to complete your registration http://myapp.com/?token=[[token(data.email=customer)]]#register
```

This following email performs the following:

* Looks up **data.email=<john@example.com>** within the **customer** Resource.
* If a record is found, it generates a temporary token and replaces `[[token(data.email=customer)]]` with that token.
* Tells the application to navigate to the ***#register*** state once the authentication has been performed.

This turns this email into something that looks like the following.

```
  To:      john@example.com
  From:    no-reply@form.io
  Subject: Register Now
  Message: Click here to complete your registration http://myapp.com/?token=lkjsdlkjs90980982l3kjlkjslkjsd....#register
```

#### Application Changes to handle Email Tokens <a href="#application-changes-to-handle-email-tokens" id="application-changes-to-handle-email-tokens"></a>

Once you have the email being sent, this single sign on URL will direct them to the Serverless application which needs to handle the token. This requires a minor change within your application to accept the token and then reset the `localStorage` value with the new token. The **\<form.io>** library will then take it from there and authenticate all future requests with that token. You can make this change by adding the following to your ***/app/config.js*** file.

```javascript
// Parse query string
var query = {};
location.search.substr(1).split("&").forEach(function(item) {
  query[item.split("=")[0]] = item.split("=")[1] && decodeURIComponent(item.split("=")[1]);
});

// This is what you will need to add to your application.
if (query.token) {
  localStorage.setItem('formioToken', query.token);
  localStorage.removeItem('formioAppUser');
  localStorage.removeItem('formioUser');
  window.history.pushState("", "", location.pathname + location.hash);
}
```

Once you have implemented this, your application should then be able to handle an automatic email authentication into your application.


# LDAP

LDAP Authentication integration provides the ability to authenticate your users directly against an LDAP service such as OpenLDAP or Active Directory.

LDAP Users are not imported into Form.io as Resources and exist only externally in LDAP. They still get assigned Form.io roles and can have ownership over forms and submissions.

## Setup

To start using LDAP for your authentication, you will need the following parameters from your LDAP provider.

| Setting       | Description                                                                                                                                                                         |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Server URL    | LDAP server URL, eg. *ldaps\://ldap.example.org:663*                                                                                                                                |
| Bind DN       | Admin connection DN, e.g. *uid=myapp,ou=users,dc=example,dc=org*.                                                                                                                   |
| Bind Password | Password for bindDN.                                                                                                                                                                |
| Search Base   | The base DN from which to search for users by username. E.g. *ou=users,dc=example,dc=org*                                                                                           |
| Search Filter | LDAP search filter with which to find a user by username, e.g. *(uid={{username}})*. Use the literal *{{username}}* to have the given username interpolated in for the LDAP search. |

### Test Configurations

If you wish to simply test the LDAP functionality, you can use the following parameters:

* Server URL: `ldap://ldap.forumsys.com:389`
* Bind DN: `cn=read-only-admin,dc=example,dc=com`
* Bind Password: `password`
* Search Base: `dc=example,dc=com`
* Search Filter: `(uid={{username}})`

With these configurations, you should then be able to use the following login credentials.

* Username: `einstein`
* Password: `password`

### Project Configuration

Once you have these configurations, you can setup LDAP within your Project Settings like so.

![](/files/dlye1iN1vQuRx49EvsWs)

By default Form.io uses email addresses to login in users so using the email attribute in the search filter is recommended unless you change the User Login form to match the search filter. For example `(mail={{username}})`

{% hint style="info" %}
LDAP user accounts are created and managed outside of the Form.io environment. Users attempting to view their account information from the Portal UI will receive an Error since Form.io does not manage this information. Create and manage LDAP accounts from the LDAP service provider or contact your system administrator.
{% endhint %}

Click **Save Project Settings** once you have these values set.

## LDAP Login Form

Next, we will create a new form that will be used to Login to LDAP. We can do this by clicking on **New Form**, and then building it as follows.

![](/files/k6GZF0TeImRKomwHyOEy)

Click **Create Form** button to create the new form.

## LDAP Login Form Access

You will now need to ensure that Anonymous users are able to "submit" this form, which will execute the actions assigned to the form. You can do this by clicking on the **Access** settings and adding the **Anonymous** role to the **Create Own** permission.

![](/files/FxQaxpNI9CgNbQDKAuYL)

## LDAP Login Action

Next, we will navigate to the Actions section of our form and first **Remove the Save Submission Action**.

After we have done, that we will add the LDAP Login action as follows.

![](/files/4DeDsIYLqCUM5vrXcna4)

Within the LDAP Login Action, you will then configure the following parameters.

![](/files/MRcFVdE4P6Z3c1IOwqfO)

If you choose the Passthrough option, any failures except for a failure to Bind the user account, will be ignored and the login information will be passed to the next form action. This allows using both LDAP and the Form.io Login action on the same form.

### Assign Roles

Next map any LDAP properties to user roles. Select the property, the matching value and the role to assign it true. Leave LDAP Property and Value blank to assign the role to all LDAP accounts.

For example:

* LDAP Property: group
* Value: Admins
* Role: Admin

Would assign the Admin role to any members of the Admins group.

The user’s DN is also mapped to the list of properties so if the DN is `dn=myname,ou=admins,dc=example,dc=org` you can do:

* LDAP Property: ou
* Value: admins
* Role: Admin

After you have the Login action set, you can save this action to add this to the form.

## Testing LDAP Login

If you provided the Test Credentials at the top of the page, then you should be able to perform the following API request within **Postman** to perform and test out an LDAP login.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

Here you will see that the **Authenticated** role has been assigned to the user object.


# OAuth

## OAuth Application Setup Overview

The most common OAuth method is leveraging the OpenID Connect framework to achieve user authentication into your application. OIDC proves to be a flexible and secure means of authenticating your user base, with a multitude of different providers available. Form.io seamlessly manages this integration, offering multiple strategies and methods to authenticate users through OIDC providers.

### Setting up an OIDC provider

Choosing an OIDC provider is the first step in the integration process. An OIDC application will then be created and configured. Remote Authentication will be configured for the Application connected to the Form.io Project. This authentication method will validate the user using credentials stored with the OIDC provider, without relying on or accessing any underlying Form.io data, decoupling the OIDC user information from the Form.io project. Form.io offers integration with many providers, including the following:

* [**OneLogin**](#one-login)
* [**Okta**](#okta)
* [**Microsoft Entra ID**](#microsoft-entra-id)
* [**Auth0**](#auth0)

{% embed url="<https://youtu.be/1-ibUSel4NE>" %}

The configuration process will vary for each OAuth/OIDC provider, however each provider generally requires the same setup. Each Provider will require the application domain to be saved to the [**Callback URL**](#user-content-fn-1)[^1]. This should be the domain the OIDC User is redirected to when they are authenticated from the OIDC Provider.

### Creating / Assigning Users and Groups

Once the application is configured, establish a user base within the authentication provider. OIDC Users can then be assigned to OIDC Groups, which allows role mapping between the OIDC Group and Form.io Role.

### **Form.io Integration**

Each will produce comparable endpoints and credentials for integrating the provider into your Form.io project. Once the OIDC application has been configured, save the following information from your OIDC provider, which will be incorporated into the Authorization settings within your Project.

{% hint style="info" %}
Access the application's **well-known endpoint** to retrieve the required endpoints for integration with the Form.io Project.
{% endhint %}

<table data-header-hidden><thead><tr><th width="157"></th><th></th></tr></thead><tbody><tr><td><a data-footnote-ref href="#user-content-fn-2"><strong>Authorize URI</strong></a></td><td><p>The endpoint where the OIDC user is asked to authenticate, granting access to the client application</p><p>Example URL: <em>https://yourcompany.oidcprovider.com/auth</em></p></td></tr><tr><td><a data-footnote-ref href="#user-content-fn-3"><strong>Token URI</strong></a></td><td>The endpoint utilized to retrieve the OAuth token from the provider after authorization has been granted.<br>Example URL: <em>https://yourcompany.oidcprovider.com/token</em></td></tr><tr><td><a data-footnote-ref href="#user-content-fn-4"><strong>User Info URI</strong></a></td><td>Examlpe URL The endpoint holding the scope of the authorizing user (or user attributes) such as email and ID stored within the OIDC provider<br>Examlpe URL: <em>https://yourcompany.oidcprovider.com/me</em></td></tr><tr><td><strong>Client ID</strong></td><td>Character string representing the client ID generated by the OAuth provider<br>Example ID: abc123def456</td></tr><tr><td><strong>Client Secret</strong></td><td>Character string representing the client ID generated by the OAuth provider<br>Example Secret: abc123def456</td></tr><tr><td><strong>Scope</strong></td><td>Communicates to the OIDC provider what information should be returned from the user to utilize for authentication. This data is compromised of various attributes and information about the User.<br>Ensure the required scopes <strong><code>openID</code></strong> and <strong><code>email</code></strong> are set within the Form.io project authentication.</td></tr></tbody></table>

Navigate to the Form.io Project's **Settings** > **Authentication > OAuth** and apply your OIDC settings to the appropriate Form.io setting fields within the **OpenID** tab.

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

#### **Configure Login Form**

The Form.io User Login form will then be modified along with an OAuth action, to support the OneLogin OIDC Authentication workflow.

#### Role Mapping

The OIDC Group associated with the OIDC user can be mapped to a Form.io role when the user authenticates. This is done by integrating the OIDC Provider group claim into the Form.io project and then mapping the OIDC Group name to a Form.io Role within the Oauth action saved to the Login Form.

### General Troubleshooting

While the OAuth provider configuration and settings fall outside of Form.io, here are some common troubleshooting tips if your OIDC authentication isn't functioning correctly.

* #### How Do I Find The URI Endpoints?

  The easiest way to identify the correct URI endpoints is to navigate to your OIDC URL and then append the '**well-known**' endpoint.

  `/.well-known/openid-configuration`

  **Example:**

  <pre><code><strong>https://yourcompany.oidcprovider.com/.well-known/openid-configuration
  </strong></code></pre>

  The response will provide all necessary URI endpoints specific to your OIDC provider as well as any scopes or claims you may want to include within your Form.io Authorization settings or **O*****A*****uth Action**.
* **Allow Origins** - The application domain that will authenticate the OIDC User. Ensure the correct client (application) domains are set within your OIDC provider utilized for authentication of the OIDC provider that will be allowed
* **Callback URL** - The URL to which Auth0 redirects users after they authenticate from the Allow Origin domain. Typically would be the same URL(s) as the Allow Orgin endpoints. In some cases, the authentication domain may be different than the domain the user is redirected to after authentication.\
  Different Providers may refer to the Callback URL differently:\
  Redirection URI, Redirection URL, Redirect URI, Redirect URL, or Callback URI
* **Connection** - Connections determine how or where the OIDC user will authenticate. Many times, Username and Password credentials stored within the OIDC provider serve as the primary means of authenticating users. However, different providers offer integrations with other OAuth-enabled applications such as Google or Facebook for authentication. It's important to ensure that a connection method is enabled for your OIDC provider; some connections might be enabled by default, depending on the provider.
* **Scope** - Check the supported Scope attributes (or claims) of your OIDC provider by searching 'scope' within the provider's 'well-known' endpoint. In every scenario, `openid` and `email` will always be included in the scope of any OIDC provider and must be configured within the OpenID settings of your project.
* **Authentication Method**- In most cases, the Authentication Method should be set to POST
* **Application Type** - Ensure the correct application type is configured for the OIDC application. In many cases, this will be a 'Web Page' or 'Single Page Application'.

## One Login

This section covers the [**OneLogin Provider**](https://developers.onelogin.com/openid-connect) OIDC application setup process and integration with the Form.io Project. Remote Authentication will be configured for the Application connected to the Form.io Project. This authentication method will validate the user using credentials stored with the OIDC provider, without relying on or accessing any underlying Form.io data, decoupling the OIDC user information from the Form.io project.

### Create and Configure Application

1. From your OneLogin Admin dashboard, create a new application by clicking the **Applications tab** and then the **Add App** button.

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

2. Select the **OpenId Connect (OIDC)** application

<figure><img src="/files/2xOKKX3ZGFrgFTobBLCe" alt=""><figcaption></figcaption></figure>

3. Give the Application a name and click the **Save** button with the default configurations

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

4. Click the **Configuration** tab to set up the application details
   * Add the **Redirect URIs** - Live endpoint of the hosted application where the response to the SAML request should be sent, after the user signs in\
     `https://app.yoursite.com`
   * Add the **Post Logout Redirect URIs** - Live endpoint that redirects a user to a specified URL after the logout process is complete\
     `https://app.yoursite.com`

The configuration should look similar to the following:

<figure><img src="/files/9VakH5xbUOp7Fb1q8VI2" alt="" width="563"><figcaption></figcaption></figure>

5. Click the **SSO** tab and set the **Authentication Method** to **POST**

<figure><img src="/files/kB8l6LpIkx2umvMCjQYK" alt="" width="380"><figcaption></figcaption></figure>

Adding a Group Parameter will enable the ability to include the user role (group) in the OIDC claim.

6. Click the **Parameter** tab
7. Click the existing **Group** parameter
8. Set the **value** to **User Roles** and the **Transform** to **Semicolon Delimited input**
9. Set the field name to **Groups**

<figure><img src="/files/0fi7Y3ScdzEGvwCpsXln" alt="" width="531"><figcaption></figcaption></figure>

### Create User

With the application configured, create a user base within the OneLogin Admin dashboard. Users can then be assigned to a Role linked with the OIDC Application, allowing OIDC and Form.io role mapping.

1. Within the OneLogin Admin dashboard, hover over the User tab and click **Users**
2. Click the **New User** button

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

3. Input the Information for the User and then click **Save User**
4. If you would like to set a password, click the **More Action** tab and **Change** **Password**
5. Generate **multiple** **users** to assign them to different roles further in the walkthrough

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

### Create and Assign Groups

With our Users in place, the next step is to create **Roles** the OIDC Users will be assigned to. This will allow us to establish mappings between OIDC roles and Form.io roles.

1. Within the OneLogin Admin dashboard, hover over the User tab and click **Roles**
2. Click the **New Role** button

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

3. Give the **Role** a name and **select** the OIDC Application the Role should be associated with
4. Click the **Save** role

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

5. Within the **Roles** tab, click the **Role** that was just created and click the **Users** Tab
6. Using the search bar, search and select all Users that should be added to the Role and click **Check**

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

5. Click the **Add To Role** button for each user
6. Click **Save**

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

#### **Assign Role To OneLogin Application**

With the Roles established, the next step is to assign the Role to the OIDC application

1. Hover over the **Application** tab and select Applications
2. Navigate to your **OIDC Application**
3. Click the **Access** tab
4. **Select** all of the **Roles** you wish to assign to the Application. Users assigned to the selected roles will be added to the Application.
5. Click **Save**

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

### **Form.io Integration**

After the OIDC application is properly configured, information from the provider will be utilized to integrate with the Form.io project and establish remote authentication. Navigate to the Form.io Project settings and apply the OIDC settings to the appropriate Form.io field settings.

#### **Client ID and Secret Key**

1. Within your OIDC Application, click the **SSO** tab
2. Copy the **Client ID**
3. Click the **Show client secret** button and **copy** the secret

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

4. Navigate to the OAuth settings within your Form.io project\
   **Settings** > **Authentication > OAuth**

![](/files/Hb9pL5QYzSTIhuCrZnyP)

5. Paste the OIDC **Client ID** and **Client Secret** to the correlated Form.io field settings

<figure><img src="/files/b9g2y8MYzcuvAGA1MRiA" alt="" width="563"><figcaption></figcaption></figure>

#### Well-Known Configuration

1. Click the **SSO** tab within the **OIDC** application
2. Click the **Well-known Configuration** button to access the OIDC application metadata

<figure><img src="/files/rfFPSfD2zyQRyAIkRAtq" alt="" width="563"><figcaption></figcaption></figure>

The well-known configuration will look something like this:

<figure><img src="/files/VtIQ1ubjYGin43j1jATJ" alt="" width="563"><figcaption></figcaption></figure>

3. Search the well-known configuration JSON file and find the following **endpoints**, then map them to the **corresponding** **fields** in your Form.io settings.

| Form.io Setting        | Well-known Configuration |
| ---------------------- | ------------------------ |
| Authorize URI          | authorization\_endpoint  |
| Token URI              | token\_endpoint          |
| Logout URI             | end\_session\_endpoint   |
| User Info (claims) URI | userinfo\_endpoint       |

4. Input the following values within the **Scope** setting\
   **openid** | **email**

{% hint style="info" %}
The `openid` and `email` scopes are **required** for all OIDC providers and must be configured in your project's OpenID settings to ensure successfully user authentication
{% endhint %}

Your settings should look something like this

<figure><img src="/files/3IRjcrFEjV1ckO1upyBB" alt="" width="563"><figcaption></figcaption></figure>

#### **Configure Login Form**

Configure the Form.io User Login form to support the OneLogin OIDC Authentication within the application.

1. Navigate to the Form.io project and **edit** the application **Login** form.
2. Add a **Button** component
3. Within the Button settings, set the **Action** to **OAuth** and **OAuth** **Provider** to **OpenID**
4. **Save** the form

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

#### **Oauth Action**

Once the Login form has been configured, an OAuth action will be added to the form to facilitate the OIDC authentication process.

1. Navigate to the **Login** form within the Form.io Project
2. Click the **Action** tab and add the **OAuth** action
3. Click the **OAuth Provider** setting and select **OpenID**
4. Click the **Action** setting and select **Remote Authentication**
5. Click the **Sign-in with OAuth Button** setting and select the **SSO** button
6. If you are mapping roles, add the following setting to the **Assign Roles** setting fields

   * The **Claim** setting will be the claim name that supports roles within the OIDC scope.
   * The **Value** setting will be the identifier for the OIDC Group.
   * The **Role** setting is the Form.io role that should be assigned to users with the given OIDC Role.<br>

   In the example below OIDC users with the **Member** role will authenticate into the application with the Form.io **Authenticated** role. OIDC users with the **Admin** role will authenticate into the application with the Form.io **Administrator** role.

| Claim (OIDC) | Value (OIDC) | Role (Form.io) |
| ------------ | ------------ | -------------- |
| groups       | Member       | Authenticated  |
| groups       | Admin        | Administrator  |

<figure><img src="/files/7KvRkbUDaravDw2NwG3X" alt=""><figcaption></figcaption></figure>

#### Role Mapping

In many cases, you may want to map the OIDC Role associated with the OIDC User to a Form.io Role. This can be done by adding the OIDC group claim within the scope setting of the Form.io Project as well as the Oauth action.

1. Navigate to the **Form.io Authorization** setting\
   **Settings** > **Authentication > OAuth**
2. Add the following values to the **Scope** setting field\
   **groups**

<figure><img src="/files/14utazFs3CafOaJZxucF" alt="" width="425"><figcaption></figcaption></figure>

3. Within the OneLogin **OIDC Application,** click the **Access** tab and take note of the **Role** **Names** assigned to the application.

<figure><img src="/files/xa8BmCgs2nTCM4WeHxaa" alt="" width="563"><figcaption></figcaption></figure>

4. Navigate to the **Role** settings and map the **OIDC** **group** (case sensitive) to the desired **Form.io Role**\
   The example below maps OIDC users with the Member role to the Form.io Authenticated role and OIDC users with the Admin role to the Form.io Administrator role

| Claim (OIDC) | Value (OIDC) | Role (Form.io) |
| :----------: | :----------: | :------------: |
|    groups    |    Member    |  Authenticated |
|    groups    |     Admin    |  Administrator |

5. **Save** the **settings**

### Testing Authentication

Test the authentication workflow to ensure it functions correctly.

1. Navigate to your Applications authentication page and click the **SSO with OIDC** button.
2. Enter the **OIDC** **credentials** into the OneLogin authentication page

<figure><img src="/files/YR4OOV6uSDu99P5FGlB7" alt="" width="344"><figcaption></figcaption></figure>

3. Once authenticated, the OIDC user should carry the **OIDC** **Group** **Role** (Member) as well as the mapped **Form.io Role ID** within the metadata of the user object.

<figure><img src="/files/71jHhjSd8OovNGH0nojq" alt="" width="563"><figcaption></figcaption></figure>

## Okta

This section covers the [**Okta OIDC**](https://www.okta.com/openid-connect/) application setup process and integration with the Form.io Project. Remote Authentication will be configured for the Application connected to the Form.io Project. This authentication method will validate the user using credentials stored with the OIDC provider, without relying on or accessing any underlying Form.io data, decoupling the OIDC user information from the Form.io project

### Create and Configure Application

1. From your [**Okta Developer**](https://developer.okta.com/) dashboard, create a new application by clicking the **Applications tab** and then the **Applications** button.
2. Click the **Create App Integration** button

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

3. Select **OIDC - OpenID Connect** from the **Sign-in method** section
4. Select **Web Application** from the **Application type** section

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

5. Apply the following configurations to the **General Settings** of the Okta OIDC Application
   * Add the **Sign-in Redirect URI** - Domain of the hosted application where Okta sends the authentication response and ID token for the sign-in\
     `https://app.yoursite.com/yourloginpage`
   * Add the **Sign-out redirect URIs** - Live endpoint that redirects a user to a specified URL after the logout process is complete\
     `https://app.yoursite.com`

The configuration should look similar to the following:

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

5. Select a **Controlled Access** setting
6. **Save** the Settings to create the application

<figure><img src="/files/SKb2weG5ChE0G3oRzPXG" alt="" width="563"><figcaption></figcaption></figure>

### Create User

Once the application is configured, establish a user base in the Okta dashboard. Users can be assigned to Okta Groups, which can then be mapped to roles in Form.io.

1. Within your Okta Admin dashboard, click the **Directory** tab and select **People**
2. Click the **Add person** button

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

3. Enter person **details** for the OIDC User
4. Click the **Password** dropdown to determine how Users password will be set
5. Click **Save** to add the User

<figure><img src="/files/568XNxQJzohGYNkhgu53" alt="" width="563"><figcaption></figcaption></figure>

### Create and Assign Groups

With Users in place, create **Groups** the OIDC Users will be assigned to. This will allow us to establish mappings between OIDC roles and Form.io roles.

1. Within your Okta Admin dashboard, click the **Directory** tab and select **Groups**
2. Click the **Add Group** button

<figure><img src="/files/8fSbaJwIZJoc2JGpGgIf" alt=""><figcaption></figcaption></figure>

3. Give your Group a **Name** and click **Save**

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

With a Group created, the next step is to assign users to the Group.

4. From the **Group** tab, select the Group to add Users to
5. Click the **Assign people** button

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

5. Assign a User to a Group by clicking the **+** button next to their username.

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

6. Within your Okta application, click the **Sign-On** tab
7. Click **Edit** under the **OpenID Connect ID Token** section

<figure><img src="/files/rHYkfPOmucyftopk8njJ" alt="" width="563"><figcaption></figcaption></figure>

8. Set the **Groups claim type** to **filter**
9. Input **groups** into the Groups claim filter
10. Set the filter type to **Matches regex**
11. Add a ".**\***" character next to the filter type
12. **Save** the settings

<figure><img src="/files/PKEvqcEEZaJ5e2j4vEyv" alt="" width="563"><figcaption></figcaption></figure>

#### **Assign Groups To Okta Application**

After establishing the Groups, the next step is to assign them to the OIDC application

1. To assign the Group, open the **Directory** tab, select the **Group,** and click the **Applications** tab
2. Click the **Assign applications** button

<figure><img src="/files/L6NSgorZgIWeajq7KuiZ" alt="" width="563"><figcaption></figcaption></figure>

3. Within the modal window, click the **Assign** button next to the **OIDC application**

<figure><img src="/files/lyTB3UWqby9u7e7uS73U" alt="" width="504"><figcaption></figcaption></figure>

### **Form.io Integration**

After the OIDC application is properly configured, information from the provider will be utilized to integrate with the Form.io project and establish remote authentication. Navigate to the Form.io Project settings and apply the OIDC settings to the appropriate Form.io field settings.

#### **Client ID and Secret Key**

1. Within your **Okta** Application, click the **General** tab
2. Copy the **Client ID** and **Client Secret**

<figure><img src="/files/lNvPR4wi2w0ukF8fmTko" alt="" width="563"><figcaption></figcaption></figure>

4. Navigate to the OAuth settings within your Form.io project\
   **Settings** > **Authentication > OAuth**

![](/files/Hb9pL5QYzSTIhuCrZnyP)

5. Paste the OIDC **Client ID** and **Client Secret** to the correlated Form.io field settings

<figure><img src="/files/b9g2y8MYzcuvAGA1MRiA" alt="" width="563"><figcaption></figcaption></figure>

#### Well-Known Configuration

1. Append the well-known endpoint to the Okta application URL

`https://dev-myapplication-admin.okta.com/.well-known/openid-configuration`

2. Open the **URL** within the **browser**.

The well-known configuration will look something like this:

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

3. Search the well-known configuration JSON file and find the following **endpoints**, then map them to the **corresponding** **fields** in your Form.io settings.

   | Form.io Setting        | Well-known Configuration |
   | ---------------------- | ------------------------ |
   | Authorize URI          | authorization\_endpoint  |
   | Token URI              | token\_endpoint          |
   | User Info (claims) URI | userinfo\_endpoint       |

   4. Input the following values within the **Scope** setting\
      **openid** | **email**

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>The <code>openid</code> and <code>email</code> scopes are <strong>required</strong> for all OIDC providers and must be configured in your project's OpenID settings to ensure user authentication</p></div>

   \
   Your settings should look something like this

<figure><img src="/files/BLDWcQ9a0wLgeFly529r" alt="" width="550"><figcaption></figcaption></figure>

#### **Configure Login Form**

Configure the Form.io User Login form to support the OneLogin OIDC Authentication within the application.

1. Navigate to the Form.io project and **edit** the application **Login** form.
2. Add a **Button** component
3. Within the Button settings, set the **Action** to **OAuth** and **OAuth** **Provider** to **OpenID**
4. **Save** the form

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

#### **Oauth Action**

Once the Login form has been configured, an OAuth action will be added to the form to facilitate the OIDC authentication process.

1. Navigate to the **Login** form within the Form.io Project
2. Click the **Action** tab and add the **OAuth** action
3. Click the **OAuth Provider** setting and select **OpenID**
4. Click the **Action** setting and select **Remote Authentication**
5. Click the **Sign-in with OAuth Button** setting and select the **SSO** button
6. If you are mapping roles, add the following setting to the **Assign Roles** setting fields

   * The **Claim** setting will be the claim name that supports roles within the OIDC scope.
   * The **Value** setting will be the identifier for the OIDC Group.
   * The **Role** setting is the Form.io role that should be assigned to users with the given OIDC Role.<br>

   In the example below OIDC users with the **Member** role will authenticate into the application with the Form.io **Authenticated** role. OIDC users with the **Admin** role will authenticate into the application with the Form.io **Administrator** role.

| Claim (OIDC) | Value (OIDC) | Role (Form.io) |
| ------------ | ------------ | -------------- |
| groups       | Member       | Authenticated  |
| groups       | Admin        | Administrator  |

<figure><img src="/files/7KvRkbUDaravDw2NwG3X" alt=""><figcaption></figcaption></figure>

#### Role Mapping

In many cases, you may want to map the OIDC Role associated with the OIDC User to a Form.io Role. This can be done by adding the OIDC group claim within the scope setting of the Form.io Project as well as the Oauth action.

1. Navigate to the **Form.io Authorization** setting\
   **Settings** > **Authentication > OAuth**
2. Add the following values to the **Scope** setting field\
   **groups**

<figure><img src="/files/14utazFs3CafOaJZxucF" alt="" width="425"><figcaption></figcaption></figure>

3. Within the Okta **OIDC Application,** click the **Access** tab and take note of the **Role** **Names** assigned to the application.

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

4. Navigate to the **Role** settings and map the **OIDC** **group** (case sensitive) to the desired **Form.io Role**\
   The example below maps OIDC users with the Member role to the Form.io Authenticated role and OIDC users with the Admin role to the Form.io Administrator role

| Claim (OIDC) | Value (OIDC) | Role (Form.io) |
| :----------: | :----------: | :------------: |
|    groups    |    Member    |  Authenticated |
|    groups    |     Admin    |  Administrator |

6. **Save** the **settings**

### Testing Authentication

Test the authentication workflow to ensure it functions correctly.

1. Navigate to your Applications authentication page and click the **SSO with OIDC** button.
2. Enter the **OIDC** **credentials** into the Okta authentication page

<figure><img src="/files/Axscz8x6SEdvq7Zp0otE" alt="" width="302"><figcaption></figcaption></figure>

3. Once authenticated, the OIDC user should carry the **OIDC** **Group** **Role** (Member) as well as the mapped **Form.io Role ID** within the metadata of the user object.

## Microsoft Entra ID

This section covers the [**Microsoft** **Entra ID**](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id) OIDC application setup process and integration with the Form.io Project. Remote Authentication will be configured for the Application connected to the Form.io Project. This authentication method will validate the user using credentials stored with the OIDC provider, without relying on or accessing any underlying Form.io data, decoupling the OIDC user information from the Form.io project

### Create and Configure Application

1. Navigate to the [**Azure Portal**](https://portal.azure.com/), click the left navigation panel, and select **Microsoft Entra ID**.

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

2. Click the **left-hand navigation bar** and select **App registrations**
3. Click the **+New registration** button

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

4. Give the application a **name**
5. Under the **Redirect URI** section, select **Web** from the dropdown, and input the application **URI**
6. Click the **Register** button

The configuration should look similar to the following:

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

#### Creating Client Secret

Once the application has been created, a Client secret will need to be generated that will be added to the Authentication OAuth integration settings within the Form.io Project.

1. Click the **Certificates and secrets** tab
2. Click the **+ New client secret** button
3. Give the secret a **Description**
4. Click the **Add** button

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

5. Copy the **Client Secret Value**

{% hint style="warning" %}
This is the only opportunity to save the **Client Secret Value**
{% endhint %}

<figure><img src="/files/5wLFNA6YKxJC2K3yzQpJ" alt=""><figcaption></figcaption></figure>

#### Adding group claim

1. Click on **Token Configuration**
2. Click **Add groups claim**
3. Check the **Groups assinged to the application** setting
4. Click **Add**

<div data-full-width="true"><figure><img src="/files/4ijaCdGzMzc3yuWNIjO3" alt="" width="563"><figcaption></figcaption></figure></div>

### Create User

Once the application is configured, establish a user base within the Entra ID dashboard. Users can be assigned to Entra ID Groups, which can then be mapped to roles in Form.io.

1. Within the **Entra ID** application, click\
   **Home** > **Microsoft Entra ID** > **Users**
2. Within the **All Users** tab click the **+New user** button

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

3. Input the User information and click the **Review + create** button

{% hint style="warning" %}
Ensure the User **email address** and **name** is set within the **Properties** tab of the user profile

Contact your Azure administrator to add the required properties to the user profile
{% endhint %}

<figure><img src="/files/mJ1okecs3aRxIeKV7hB3" alt="" width="475"><figcaption></figcaption></figure>

4. Create several other users to test Group and Role mapping detailed in the next section.

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

### Create and Assign Groups

With Users in place, the next step is to create **Groups** the Entra ID Users will be assigned to. This will allow us to establish mappings between EntraID groups and Form.io roles.

1. Within the Azure dashboard, click the left-hand navigation bar, **Groups**, and **All Groups** tab
2. Click the **New group** button

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

3. Give the Group a **Group Name** and keep the remaining settings at their default values

<figure><img src="/files/nKRGdsqNac7JqaY9Q2PJ" alt="" width="563"><figcaption></figcaption></figure>

4. Click the **No Members Selected** button to assign users
   * **Search** for the User created in the previous section
   * **Select** the User
   * Click the **Select** button

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

5. Click the **Create** button
6. Follow the same steps to create additional **Groups**

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

#### **Assigning Groups to Application**

With the Groups established, the next step is to assign the Groups to the Entra ID application.

{% hint style="warning" %}
Groups mappings for Entra ID are supported for formio-server version 9.6.x and above
{% endhint %}

{% hint style="warning" %}
A proper license is required to add Groups to your Entra ID application
{% endhint %}

1. Navigate back to your **Entra ID OIDC** application
2. Select the **Users and groups** tab then click the **+ Add user/group** button
3. On the next screen, click the **None Selected**

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

4. Select the **Groups** to add to the application
5. Click the **Select** button at the bottom of the screen and then **Assign** on the following page

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

After assigning the Groups, you should see the Groups displayed within the User and Groups tab of the Entra ID application. Users assigned to the selected groups will be associated with the Entra ID Application.

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

### **Form.io Integration**

Once the OIDC application is properly configured, information from the application will be used to integrate the application with the Form.io project. Navigate to the Form.io Project settings and apply the OIDC settings to the appropriate Form.io field settings.

#### **Client ID and Secret Key**

1. Navigate to the **Entra ID** dashboard, click **App registrations**, and select your application

<figure><img src="/files/5sOGNYUCKnPtEzwee8rV" alt=""><figcaption></figcaption></figure>

2. Within your Entra ID Application, click the **Overview** tab
3. Copy the **Application (client) ID** value and **Secret** from the [**Client Secret Step**](#creating-client-secret)

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

4. Navigate to the OAuth settings within your Form.io project\
   **Settings** > **Authentication > OAuth**

![](/files/Hb9pL5QYzSTIhuCrZnyP)

5. Paste the OIDC **Application** (**Client) ID** and **Client Secret** to the correlated Form.io field settings

<figure><img src="/files/b9g2y8MYzcuvAGA1MRiA" alt="" width="563"><figcaption></figcaption></figure>

#### Well-Known Configuration

1. Within Entra ID, click the **App registrations** tab and select the **OIDC Application**
2. Click the **Overview** tab and then **Endpoints**
3. **Copy** the ***OpenID Connect metadata document*** ULR and open it in a browser

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

The Endpoints will look something like this:

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

4. Add the following endpoints from the Well-known configuration to the correlated field settings

<table><thead><tr><th width="350.10015869140625">Form.io Setting</th><th>Well-known Config</th></tr></thead><tbody><tr><td>Authorize URI</td><td>authorization_endpoint</td></tr><tr><td>Token URI</td><td>token_endpoint</td></tr><tr><td>User Info (claims) URI</td><td>userinfo_endpoint</td></tr></tbody></table>

5. Input the following values within the **Scope** setting **openid** | **email**

{% hint style="info" %}
The `openid` and `email` scopes are **required** for all OIDC providers and must be configured in your project's OpenID settings to ensure user authentication
{% endhint %}

Your Form.io Authorization settings should look something like this

<figure><img src="/files/7iIoEDBk8t9khSwU1BQe" alt=""><figcaption></figcaption></figure>

**Configure Login Form**

Configure the Form.io User Login form to support the Auth0 Authentication within your application.

1. Navigate to the Form.io project and **edit** the application's **Login** form.
2. Add a **Button** component
3. Within the Button settings, set the **Action** to **OAuth**
4. Set the **OAuth** **Provider** to **OpenID**
5. **Save** the form

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

**OAuth Action**

Once the Login form has been configured, an OAuth action will be added to the form to facilitate the OIDC authentication process.

1. Navigate to the **Login** form within the Form.io Project
2. Click the **Action** tab and add the **OAuth** action
3. Click the **OAuth Provider** setting and select **OpenID**
4. Click the **Action** setting and select **Remote Authentication**
5. Click the **Sign-in with OAuth Button** setting and select the **OIDC Button**
6. If you are mapping roles, add the following setting to the **Assign Roles** setting fields

   * The **Claim** setting will be the claim name (**Group** **Object ID)** that supports roles within the OIDC scope.
   * The **Value** setting will be the **Group ID** for the Entra ID Group.

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

   * The **Role** setting is the Form.io role that should be assigned to users with the given OIDC Role

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

7. **Save** the Action

### Testing Authentication

Test the authentication workflow to ensure it functions correctly.

1. Navigate to your Applications authentication page and click the **SSO with OIDC** button.
2. Enter the **OIDC** **credentials** into the **Microsoft** authentication page

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

3. Once authenticated, the OIDC user should carry the **OIDC** **Group** **Role** (group id) as well as the mapped **Form.io Role ID** within the metadata of the user object.

## Auth0

This section explains how to set up the [**Auth0 Provider** ](https://auth0.com/)OIDC application and integrate it with the Form.io Project. Remote Authentication will be configured for the application linked to the project, allowing user validation through credentials stored with the OIDC provider. This ensures authentication occurs independently of any Form.io data, keeping OIDC user information fully decoupled from the Form.io project.

### Create and Configure Application

1. Access the [**Auth0 Admin dashboard**](https://manage.auth0.com/dashboard)
2. Click the **Applications** tab
3. Click the **+Create Application** button

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

4. Give the Application a **Name** and click the **Create** button

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

5. Within the Application, click the **Setting** tab

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

5. Navigate to the Application URIs section and add the application endpoint to the **Allowed Callback URLs**\
   `https://myapplication.com/dashboard`

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

6. **Save** the settings

### Create User

After configuring the application, set up your user base in the Auth0 dashboard. Assign users to Auth0 Roles, which can then be mapped to corresponding Form.io Roles.

1. In the Auth0 admin dashboard, navigate to **User Management** and select **Users**
2. Click the **+Create User** button

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

3. Input user **credentials** and click **Create**

<figure><img src="/files/hSiHzS56hkwumQMmGcY1" alt="" width="483"><figcaption></figcaption></figure>

4. Add **additional** **users** to assign to the roles that will be configured in the next step.

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

### Create and Assign Roles

Once users are set up, the next step is to create roles for OIDC users. These roles establish the mappings between OIDC roles and Form.io role assignments.

1. Under the **User** **Management** tab, click **Roles**
2. Click **Create Role**
3. Enter a **Name** and **Description** for the role, then click **Create**.

<figure><img src="/files/keQVJqZewMR64DpgGuHl" alt="" width="480"><figcaption></figcaption></figure>

4. Within the Role tab, select a **Role** created in the previous step

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

5. Click on the **Users** tab
6. Click **Add Users**

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

7. Search and select the user to add to this Role and click **Assign**

<figure><img src="/files/NqFBeUVkRuuUqqACjP7K" alt="" width="482"><figcaption></figcaption></figure>

8. Assign users to additional Roles you might have created in the previous steps

### Implementing Custom Actions to Assign Form.io Roles

In order to assign the Roles created in Auth0 and map them to a Form.io login, a custom Post-Login Action in Auth0 to required to map Form.io roles in the ID token. After creating and coding the action, deploy it and attach it to the Post-Login trigger to ensure it runs after user login.

1. Under the **Actions** tab click **Library**
2. Click the **Create Action** dropdown then select **Create Custom Action**

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

3. Give the action a **Name**
4. Set the **Trigger** to **Login / Post Login**
5. Set **Runtime** to **Node 18** and click **Create**

<figure><img src="/files/qqxeiSPoqRzubkR6AGGi" alt="" width="453"><figcaption></figcaption></figure>

6. **Add** the following **code** within the **onExecutePostLogin** function

```typescript
exports.onExecutePostLogin = async (event, api) => {
  if(event.authorization){
    api.idToken.setCustomClaim('formioRoles', event.authorization.roles);
  }
};

```

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

{% hint style="warning" %}
Note: you cannot .setCustomClaim('groups', ...) or .setCustomClaim('roles', ...)
{% endhint %}

7. Click the **Deploy** button
8. Under the **Actions** tab, click on **Triggers**
9. Click the **post-login** trigger
10. Click the **Custom** tab
11. Drag your action in between **Start** and **Complete**
12. Click **Apply**

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

### **Form.io Integration**

Once the OIDC application is properly configured, information from the application will be used to integrate the application with the Form.io project. Navigate to the Form.io Project settings and apply the OIDC settings to the appropriate Form.io field settings.

#### **Client ID and Secret Key**

1. Navigate to your Auth0 Application and click the **Settings** tab
2. Copy the **Client ID** and **Client Secret**

<figure><img src="/files/7ynwbCPkyKci45eQf6vT" alt=""><figcaption></figcaption></figure>

3. Navigate to the **Form.io Project** Auth0 authentication should be applied to
4. Access the **OAuth** settings\
   **Settings** > **Authentication > OAuth > OpenID**

![](/files/Hb9pL5QYzSTIhuCrZnyP)

5. Paste the OIDC **Client ID** and **Client Secret** to the correlated Form.io field settings

<figure><img src="/files/b9g2y8MYzcuvAGA1MRiA" alt="" width="563"><figcaption></figcaption></figure>

#### Well-Known Configuration

1. Within your Auth0 Application, click the **Settings** tab
2. Scroll down the Settings page and expand the **Advanced Settings**
3. Click the **Endpoints** tab

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

The endpoint information will look something like this:

<figure><img src="/files/fuGvzFiX4WQVJSEjFB23" alt="" width="563"><figcaption></figcaption></figure>

4. Add the following endpoints Well-known configuration endpoints and map them to the **corresponding** **fields** in your Form.io settings.

| Form.io Setting        | Well-known Configuration |
| ---------------------- | ------------------------ |
| Authorize URI          | OAuth Authorization URL  |
| Token URI              | OAuth Token URL          |
| User Info (claims) URI | OAuth User Info URL      |

5. Input the following values within the **Scope** setting\
   **openid** | **email**

{% hint style="warning" %}
The `openid` and `email` scopes are **required** for all OIDC providers and must be configured in your Form.io project's OpenID settings to ensure successful user authentication."
{% endhint %}

Your settings should look something like this

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

#### **Configure Login Form**

Configure the Form.io User Login form to support the Auth0 Authentication within your application.

1. Navigate to the Form.io project and **edit** the application's **Login** form.
2. Add a **Button** component
3. Within the Button settings, set the **Action** to **OAuth**
4. Set the **OAuth** **Provider** to **OpenID**
5. **Save** the form

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

#### **OAuth Action**

Once the Login form has been configured, an OAuth action will be added to the form to facilitate the OIDC authentication process.

1. Navigate to the **Login** form within the Form.io Project
2. Click the **Action** tab and add the **OAuth** action
3. Click the **OAuth Provider** setting and select **OpenID**
4. Click the **Action** setting and select **Remote Authentication**
5. Click the **Sign-in with OAuth Button** setting and select the **OIDC Button**
6. If you are mapping roles, add the following setting to the **Assign Roles** setting fields

   * The **Claim** setting defines the claim name that carries role information within the OIDC scope. Use the same name specified in **Step 6** of the [**Custom Action**](#implementing-custom-actions-to-assign-form.io-roles) section in the Auth0 setup.

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

   * The **Value** setting will be the identifier for the OIDC Group. Use the same **Role** name specified in **Step 3** of the [**Create and Assign Roles**](#create-and-assign-roles) section in the Auth0 setup.
   * The **Role** setting is the Form.io role that should be assigned to users with the given OIDC Role.
7. **Save** the Action settings

{% hint style="info" %}
In the example below OIDC users with the **Member** role will authenticate into the application with the Form.io **Authenticated** role. OIDC users with the **Admin** role will authenticate into the application with the Form.io **Administrator** role.
{% endhint %}

| Claim (OIDC) | Value (OIDC) | Role (Form.io) |
| ------------ | ------------ | -------------- |
| formioRoles  | admin role   | Administrator  |
| formioRoles  | user role    | Authenticated  |

<div data-full-width="false"><figure><img src="/files/5fdf4rDSImC4SymJ3Mbf" alt=""><figcaption></figcaption></figure></div>

### Testing Authentication

Test the authentication workflow to ensure it functions correctly.

1. Navigate to your Applications authentication page and click the **SSO with OIDC** button.
2. Enter the **OIDC** **credentials** into the OneLogin authentication page

<figure><img src="/files/l7S7y1NcSawf8SCBoBvo" alt="" width="305"><figcaption></figcaption></figure>

3. Once authenticated, the OIDC user should carry the **OIDC** **Group** **Role** (Member) as well as the mapped **Form.io Role ID** within the metadata of the user object.

## Token Swap

One type of application design is where form.io forms are embedded in an existing application that already has OAuth authentication built into it. In this type of application, the OAuth token can be exchanged for a form.io token to enable all future interactions with form.io to be authenticated using the new form.io token.

To do this, you should have an existing Bearer (or other) authorization token from the OAuth provider. You also need to set up the OpenID and OpenID Connect settings in your project.

Then, instantiate the Formio library with your project URL and call the currentUser endpoint with your authorization header.

```json
var header = new Formio.Headers();
header.set('Authorization', 'Bearer 2e762950-9498-4079-a699-xxxxxxxxxxxx');

Formio.setBaseUrl('https://yourdomain.com');
Formio.setProjectUrl('https://yourdomain.com/yourproject');
var formio = new Formio('https://yourdomain.com/yourproject');
formio.currentUser({
  external: true,
  header: header,
});
```

{% hint style="info" %}
To perform a Token Swap, it is required to expose the /UserInfo endpoint
{% endhint %}

Form.io will use the authorization token to request the OAuth endpoint, receive the user information, and create a new form.io token that is passed back to the form.io library and used on subsequent requests.

## OIDC - Developer Portal

To enable SSO in the Developer Portal, simply apply all the configurations detailed above, but apply the configurations to the **Portal Base** project. Utilizing the Remote Authentication method will set up authentication for the Developer Portal application, eliminating the necessity for resource-based authentication. Follow the link below for a detailed walkthrough:

**SSO Authentication Into Developer Portal Using OIDC**

## OIDC - Form Manager Application

The same concepts above can be applied to the Form Manager application. Since the Form Manager utilizes the Admin Login form for authentication, the only difference between this workflow and the previous SSO example is the form being modified is the Admin Login form instead of User Login.

#### OIDC Provider Application

1\. Create an application within your OIDC provider (in this example auth0) and choose Single Page application type.

![](https://gblobscdn.gitbook.com/assets%2F-MPHoF2HwOA0s5HV_AIB%2F-MbHdEabkqwq1Igu9AC5%2F-MbHgIgCB2XOuZmHLA6H%2Fimage.png?alt=media\&token=168eec8a-3001-470f-b339-f21daad47ad7)

![](https://gblobscdn.gitbook.com/assets%2F-MPHoF2HwOA0s5HV_AIB%2F-MbHdEabkqwq1Igu9AC5%2F-MbHfJD7-KiXfb3TBEz6%2Fimage.png?alt=media\&token=b02dc97f-99fa-48d9-94d4-c98ef8f4719a)

#### Open ID Application Configuration

Gather the Client ID and secret as well as the necessary endpoints found within the [**well-known** ](#how-do-i-find-my-uri-endpoints)endpoint for your application.

![](https://gblobscdn.gitbook.com/assets%2F-MPHoF2HwOA0s5HV_AIB%2F-MbHdEabkqwq1Igu9AC5%2F-MbHhY_XfB7mZkBl9O9Z%2Fimage.png?alt=media\&token=ded09e8f-6fe1-4497-a6df-8a252f353979)

```
https://dev-abcdefghij.us.auth0.com/.well-known/openid-configuration
```

```
{
    "issuer": "https://dev-abcdefghij.us.auth0.com/",
    "authorization_endpoint": "https://dev-abcdefghij.us.auth0.com/authorize",
    "token_endpoint": "https://dev-abcdefghij.us.auth0.com/oauth/token",
    "device_authorization_endpoint": "https://dev-abcdefghij.us.auth0.com/oauth/device/code",
    "userinfo_endpoint": "https://dev-abcdefghij.us.auth0.com/userinfo",
    "mfa_challenge_endpoint": "https://dev-abcdefghij.us.auth0.com/mfa/challenge",
    "jwks_uri": "https://dev-abcdefghij.us.auth0.com/.well-known/jwks.json",
    "registration_endpoint": "https://dev-abcdefghij.us.auth0.com/oidc/register",
    "revocation_endpoint": "https://dev-abcdefghij.us.auth0.com/oauth/revoke",
    "scopes_supported": ["openid", "profile", "offline_access", "name", "given_name", "family_name", "nickname", "email", "email_verified", "picture", "created_at", "identities", "phone", "address"],
    "response_types_supported": ["code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token"],
    "code_challenge_methods_supported": ["S256", "plain"],
    "response_modes_supported": ["query", "fragment", "form_post"],
    "subject_types_supported": ["public"],
    "id_token_signing_alg_values_supported": ["HS256", "RS256"],
    "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"],
    "claims_supported": ["aud", "auth_time", "created_at", "email", "email_verified", "exp", "family_name", "given_name", "iat", "identities", "iss", "name", "nickname", "phone_number", "picture", "sub"],
    "request_uri_parameter_supported": false
}
```

#### Form.io Project Configuration

Navigate to the Form.io Project the Form Manager application is connected to. Navigate to the **Authorization** > **OAuth** > **OpenID** settings.

![](/files/C4cIcWA9xlgmDEMUFHjf)

Apply the information from the OIDC application and **well-known** endpoint.

![](/files/6V8g7dom0THMV9ZgY60F)

#### Setting Up OpenID Login Button

1. Within your Project, navigate to the **Admin** Login form.
2. Add a **Button Component**
   * Select the **OAuth** action
   * Select the **OpenID** provider
   * Save settings.

![](/files/Cy1KAYDPzY1ouVAbdlrZ)

3. Navigate to the **Action** tab and add the **Oauth** Action.

![](/files/uMTMWF9nGGqv5JTFVcWV)

4. Configure the **OAuth** action
   * Select your **OAuth** provider
   * Select the **Remote** **Authentication** Action
   * Select the **SSO** button within the Admin login form
   * Since the Form Manager requires Administrative users, select the **Administrator** Role

![](/files/3wotot5jdJlP2wYPaFuj)

#### **Workflow Testing**

1. Launch the **Form Manager** application
2. Click the **Login with OIDC** button
3. Enter your **OIDC** User **credentials**

![](/files/kOBFH0eZ3rXO5vxPovAR)

You should authenticate into the Form Manager application

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

[^1]: The URL to which Auth0 redirects users after they authenticate from the Allow Origin domain

    Other terms for the Callback:

    Redirection URI

    Redirection URL

    Redirect URI

    Redirect URL

    Callback URI

[^2]: authorization\_endpoint

[^3]: token\_endpoint

[^4]: userinfo\_endpoint


# SAML

## Introduction

Simplify and centralize your user authentication process by integrating SAML into your Form.io project. This integration allows you to configure your application login forms to support SAML SSO authentication for your application users.

**SAML Provider**

Choosing a SAML provider is the first step in the integration process. A SAML application will then be created and configured. Form.io offers integration with many providers, including the following:

* [#onelogin](#onelogin "mention")
* [#okta](#okta "mention")
* [#microsoft-entra-id](#microsoft-entra-id "mention")
* [#autho](#autho "mention")

***

[**Passport Configuration**](#saml-passport-config)

Once a provider has been chosen and a SAML application has been created, the next step is to integrate the SAML application with your Form.io project. The integration process involves transferring specific credentials and endpoints from the SAML application and then using that information to construct a Passport Configuration JSON object that will be saved within the Form.io Project connected to your application. Form.io utilizes the Node.js SAML Authentication library.

{% hint style="info" %}
Form.io utilizes the Node.js SAML Authentication library.\
[**Click Here** ](https://github.com/node-saml/node-saml)for documentation and a full list of SAML Passport properties
{% endhint %}

***

[**Form.io Authentication Configuration**](#form.io-authentication-configuration)

After applying the correct information from your SAML Provider to your Project's authorization settings, the Form.io authentication form embedded in your application will be configured to support SAML SSO authentication.

***

[**Portal Base SSO with SAML**](/deploy/portal-base-project/portal-sso)

The following documentation is centralized around applying SAML to a client-based application connected to the Form.io project. The same concepts detailed in this documentation can also be applied to the Form.io Portal Base project that controls your Developer Portal to allow Form.io users to utilize SAML SSO to authenticate into the Form.io environment.

***

### Video Tutorial

The following video demonstrates the creation of a SAML application, integration with Form.io, and configuring the authentication form that will instigate the SAML authentication process for the client application. OneLogin serves as the SAML Provider in this video, however, the same principles can be applied to other Providers.

{% embed url="<https://youtu.be/PTOFFHnhiWA>" %}

## How does Form.io SAML Work

SAML authentication uses settings in the project to communicate with an external SAML identity provider (IdP) in order to authenticate the user into the Form.io environment. The project roles can be mapped to SAML roles via the SAML configuration in the project. When creating the login form, add custom JavaScript to trigger a service provider-initiated SAML authentication flow, that allows users to authenticate using the IdP. The IdP returns a JWT to the user. The following shows step-by-step on how this process works.

<figure><img src="/files/fV8VzsfYjYAiajU7lhFm" alt="" width="375"><figcaption></figcaption></figure>

1. The **User** navigates to {{baseUrl}}/{{projectAlias}}/saml/sso (Usually via a button on the form that calls `Formio.ssoInit('saml')`)
2. The **Form.io Server** processes the SAML configuration settings into a SAML request .XML document and encodes it into a redirect link to the **IdP Server** for authentication.\
   The redirect link looks something like the following:\\

   {{Entry Point}}?SAMLRequest= {{encoded xml document}}& relayState={{your relay state}}

{% hint style="info" %}
The relayState is used to navigate the user back to the SP login page after IdP login and is automatically set to the URL of your SP login page. This can be modified via the relay option when creating the form.
{% endhint %}

3. The user is redirected to a login page provided by the **IdP Server** (if the SAML request was valid).
4. Upon successful login, the **IdP Server** sends the user to an HTML document containing JavaScript that makes a POST request containing the SAML response .XML document to the callback URL specified in the SAML configuration.\
   The callback URL should point to the assertion consumer service endpoint (ACS) and look something like the following:\
   {{baseurl}}/{{projectUrl}}/saml/acs
5. The browser (**User**) executes the JavaScript to make the POST to the ACS endpoint (as described above).
6. The ACS endpoint on the **Form.io Server** processes the SAML response .XML document, verifying that the document and assertions are valid using the certificate specified in the SAMLE configuration.\
   It then takes the assertions given by the SAML response XML and generates a Formio JWT token. The server then redirects the user to the relay URL, with the JWT added as a query parameter. It should look something like the following:\
   {{relay}}?saml={{JWT}}
7. With the JWT from the query parameter, call `Formio.ssoInit('saml')` again to add the JWT to the browser's local storage.\
   The user isnow authenticated to access **Form.io Server** resources!

## General Troubleshooting

While the SAML provider configuration and settings fall outside of Form.io, here are some common errors and troubleshooting tips if your SAML authentication isn't functioning correctly.

### Required Config Parameters

The only required fields needed by node-saml are...

* Issuer - The unique identifier you give when sending saml requests
* Cert - Used to verify the saml response document and assertions in the saml response

All other fields are based on the configuration you have set in your IdP. This can very widely depending on what IdP you are using. A couple of recommended config parameters are...

* Entry Point - The url of your IdPs login endpoint
* Callback Url - The url that the saml response is sent to
* Want Assertions Signed - Check this if you want to verify that your assertions are signed correctly.\
  Note: Make sure your IdP is signing assertions if you have this checked or an error will occur
* Want Authn Response Signed - Check this if you want the top level of your saml response document to be signed\
  Note: Make sure your IdP is signing the top level of your saml response xml or an errro will occur

### **Errors**

#### **Invalid Signature**

* **Cause**: The signature in the SAML response or assertion could not be verified, often due to mismatched certificates between the IdP and Form.io or an unsupported signature algorithm.
* **Solution**: Ensure that the public certificate used by the IdP matches the one configured in Form.io and that the IdP supported signature algorithm (preferably RSA-SHA256).
* Ensure the cert from the Idp matches the cert saved in the Form.io SAML settings\
  \
  Form.io typically signs:

  * **SAML Assertions** (the payload that contains authentication and user details).
  * Optionally, **SAML Responses** (the overall message containing the assertion).

  If the SAML signature isn't validated correctly, you may need to check the certificate used in the IdP configuration and ensure the hashing algorithm is compatible (e.g., SHA-256).

#### **Audience URI mismatch**

* **Cause**: The Audience URI in the SAML response from the IdP does not match what Form.io expects.
* **Solution**: Verify that the **Audience URI** in the IdP settings matches the URL of your Form.io application. This typically looks like:

  ```arduino
  http://myapplicationdomain.com
  ```
* Ensure there are no typos, extra slashes, or case-sensitivity issues.

#### **SAML Assertion is not valid**

* **Cause**: The SAML assertion may have expired, the certificate used to sign the assertion could be invalid, or the assertion lacks the necessary conditions.
* **Solution**: Check the SAML assertion for correct timestamps and validity. Ensure that the IdP is signing the assertion properly and that Form.io can validate the signature.
* Ensure the 'Email Path' and 'Roles Path' in the Form.io SAML settings align with the email and group parameters provided by the IdP. Often, these parameters will be set to 'email' and 'groups.'

#### **Invalid RelayState**

* **Cause**: The RelayState parameter in the SAML request is either missing or invalid.
* **Solution**: Ensure that the RelayState parameter is properly set in the SAML authentication request, and that it is being passed correctly between the IdP and Form.io. This will often time be the hosted application domain.

#### **NameID or Groups not found in SAML Assertion**

* **Cause**: The SAML assertion does not contain the `NameID or groups` attribute, which is essential for identifying the user or user SAML group.
* **Solution**: Ensure the IdP is configured to include the `NameID or group` attribute in the SAML assertion, typically within the `<Subject>` element.

#### **Missing Attribute Statement**

* **Cause**: The SAML assertion is missing required attributes that Form.io expects (e.g., email, username, or custom attributes).
* **Solution**: Check the IdP configuration to ensure it is passing the required user attributes in the SAML assertion.

### How to Troubleshoot:

1. **Use a SAML Tracing Tool**: Browser extensions like **SAML Chrome Panel** or **SAML-tracer** (Firefox) can capture SAML requests and responses for analysis.
2. **Check Configuration**: Verify that both the IdP and Form.io configurations are aligned, particularly regarding the Audience URI, ACS URL, and signature settings.
3. **Review Logs**: Check the IdP and SP logs for more detailed error messages that might provide clues to what went wrong.
4. **Password Configuration -** Utilize the **Passport Config** over the **SAML Metadata** when configuring the SAML integration settings within the Form.io Project.

These error messages are typically due to configuration mismatches or signing issues, and can usually be resolved by carefully reviewing the settings on both sides.

## OneLogin

This section covers the [**OneLogin Provider**](https://developers.onelogin.com/saml) SAML application setup process and integration with the Form.io Project.

### **Create and Configure Application**

1. From your OneLogin Admin dashboard, create a new application by clicking the **Applications tab** and then the **Add App** button.

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

2. Select the **SAML Custom Connector (Advanced)** for **SAML2.0** application

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

3. Give the Application a name and click the **Save** button with the default configurations

![](/files/mpN3EFmA4f8y4orvERXt)

4. Click the **Configuration** tab to set up the application details
   * Add the **RelayState** (optional) - Live endpoint of the hosted application\
     `https://app.yoursite.com`
   * Add the **Audience (EntityID)** - Live endpoint of the hosted application\
     `https://app.yoursite.com`
   * Add the **ACS (Consumer) URL Validator** - [**Live Endpoint**](/admin/projects/project-ui) of the Form.io Project with form.io\\/saml\\/acs appended at the end of the URL. Backslash characters `\` should be added in front of all forward slash characters `/`\
     `https:\/\/myproject.domain\/abc123\/saml\/acs`
   * Add the **ACS (Consumer) URL** - [**Live Endpoint**](/admin/projects/project-ui) of the Form.io Project with form.io/saml/acs appended at the end of the URL.\
     `https://myproject.domain.com/abc123/saml/acs`

The configuration should look similar to the following:

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

5. Within the Configuration tab, set the **SAML signature element** to the **Both** setting

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

#### **Configuring Parameters**

6. Click the **Parameters** tab and ensure the following parameter is set (this should be set by default) **NameID** **value** field is configured with the **Email** value
7. Click the **Paramter** Tab, click the **+** button to add a new Parameter
   * Set the Field Name to **groups** (case sensitive)
   * Set the Value to **User Roles**
   * Check the **Include in SAML assertion** flag
   * **Save** the Parameter

<figure><img src="/files/sH96zTX3fs1GtQ11yl9n" alt="" width="375"><figcaption></figcaption></figure>

8. The application should have two parameters set\
   **NameID Value** (created by default with the application)\
   **group** parameter created in the previous step
9. **Save** the application

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

### Create Users

With the application configured, create a user base within the OneLogin Admin dashboard. Users can then be assigned to a Role linked with the SAML Application, enabling mapping between SAML Groups and Form.io roles.

1. Within the OneLogin Admin dashboard, hover over the User tab and click **Users**
2. Click the **New User** button

![](/files/2KRKjLFlbdQV7qyhdFXv)

3. Input the Information for the User and then click **Save User**
4. Click the **More Action** tab and set a **Password** for the User
5. Generate multiple users to assign them to different roles that will be created in the next step

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

### Create & Assign Groups

With our Users in place, the next step is to create **Roles** the SAML Users will be assigned to. This will allow us to establish mappings between SAML Roles (Groups) and Form.io roles.

1. Within the OneLogin Admin dashboard, hover over the User tab and click **Roles**
2. Click the **New Role** button
3. Give the **Role** a name and select your SAML Application the Role should be associated with
4. Click the **Save** role

![](/files/r0iPItFDYut1fbfKHAoa)

5. Within the **Roles** tab, click the **Role** that was just created and click the **Users** Tab
6. Using the search bar, search and select all Users that should be added to the Role and click **Check**

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

7. Click the **Add To Role** button for each user
8. Click **Save**

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

#### **Assign Role To Application**

With the Roles established, the next step is to assign the Role to the SAML application

1. Hover over the **Application** tab and select Applications
2. Navigate to your **SAML Application**
3. Click the **Access** tab
4. **Select** all of the **Roles** you wish to assign to the Application\
   Users assigned to the selected roles will be associated with the Application.
5. Click **Save**

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

### Passport Configuration

Once the SAML application setup is finalized, XML data will be extracted from the application and utilized for building the Passport Configuration. This JSON configuration will be saved to the Form.io Project to complete the integration.

{% hint style="info" %}
[**Click Here**](#saml-passport-config) for more information about SAML Passport Configurations
{% endhint %}

#### **Download XML File**

1. Navigate to the **OneLogin** application
2. Click the **More Actions** tab and click the **SAML Metadata** button to download the XML info

<figure><img src="/files/6vFU4IsrbBXLOhJUPYQi" alt=""><figcaption></figcaption></figure>

3. Store the XML information as it will be used to construct the **Passport Config**

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

4. Construct the **Passport Config JSON** object. Search the XML file for the property titles within the example below and input the data accordingly.
   * The **identityProviderUrl** and **entryPoint** endpoint can be found by searching the **SingleSignOnService** HTTP-REDIRECT endpoint
   * The **logoutUrl** endpoint can be found by searching **SingleLogoutService**
   * The **cert** can be found by searching the **X509Certificate**
   * The **identifierFormat** can be found by searching **NameIDFormat**
   * The **audience** must match the **Audience (EntityID)** endpoint within the **Configuration** tab within your OneLogin SAML application.
   * The **issuer** can be found by searching the **entityID**

{% hint style="info" %}
Quickly generate the JSON object by utilizing the [**SAML Passport Generator**](#saml-passport-generator) found within the SAML Settings of the Form.io Project.
{% endhint %}

```
{"identityProviderUrl": "https://form-dev.onelogin.com/trust/saml2/http-redirect/sso/abc-123", 
"entryPoint": "https://form-dev.onelogin.com/trust/saml2/http-redirect/sso/abc-123", 
"logoutUrl": "https://form-dev.onelogin.com/trust/saml2/http-redirect/slo/abc-123", 
"cert": "abc123", 
"identifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", 
"audience": "https://app.yoursite.com", 
"issuer": "https://app.onelogin.com/saml/metadata/abc-123"}
```

### **Form.io Integration**

With the Passport Config JSON object constructed, the Form.io project can now be configured.

1. Within the Form.io Project, click **Settings** > **Authentication** > **SAML**
2. Click the **Authorization Settings** tab

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

3. Scroll down and paste the **Passport Config** JSON from the previous step

<figure><img src="/files/2OlnISK43BoIpsxWsAkF" alt="" width="563"><figcaption></figcaption></figure>

4. Click the **Configuration** tab and add the following to the **Email Path** setting field\
   `email`
5. Click the **Save Settings**

#### **Role Mapping**

In many cases, you may want to map the SAML Role associated with the SAML User to a Form.io Role. Apply the following configurations to configure the Role mappings.

6. Within the Form.io SAML settings, click the Configuration tab and set the following to the **Role Path**\
   [`groups`](#user-content-fn-1)[^1]

![](/files/UDBh2UxUDCuD3IH5D43A)

7. Within your OneLogin **SAML Application,** click the **Access** tab and take note of the **Role** **Names** assigned to the application.

![](/files/QC23pYhhneDtECtaLkEf)

8. Back to the Form.io SAML settings, scroll down to the **Role Mapping** setting
9. Map **SAML** **Roles** (case sensitive) to the desired **Form.io Roles**
10. **Save** your settings

![](/files/y333qlRTahPM01sMuOVu)

After authentication, SAML users assigned to the **Admin** SAML role will obtain the Form.io **Administrator** role, while those assigned to the **Member** role will receive the Form.io **Authenticated** role. This can be seen by inspecting the user object within the dev console.

![](/files/aQ3N07DIQg2NIAWmaWTQ)

#### **Authentication Configuration**

The final step is to configure the Form.io Login form embedded in your application to support SAML. Alternatively, you can modify your application to support a similar process. Follow the link below for documentation.

[**Form.io Authentication Configuration**](#form.io-authentication-configuration)

## Okta

This section covers the [**Okta** ](https://okta.com)SAML application setup process and integration with the Form.io Project.

### Create and Configure Application

1. From your Okta Admin dashboard, create a new Okta application by clicking **Applications** and then **Create App Integration**.

![](/files/1YwJQTcLtqCYlOWl44Mh)

2. Select **SAML 2.0** from the modal window and click **Next**

![](/files/yoo7vbm4oZ3XXq5nvlHv)

3. Provide a **Name** for the application and click **Next**

![](/files/tDbtnI9qOohUVaeAz306)

4. Provide the **Single Sign-On URL**\
   Copy your Form.io project endpoint and append **/saml/acs** at the end of the URL.\
   \
   \&#xNAN;*Example*: if your project API endpoint is\
   \*\*<https://myproject.domain.com/abc123**\\>
   then your Assertion Consumer Service URL will be the following.

```
https://myproject.domain.com/abc123/saml/acs 
```

5. Provide the **Audience URI**\
   Copy your Form.io project endpoint and append the path **/saml/metadata** at the end of the URL.\
   \
   \&#xNAN;*Example*: if your project API endpoint is\
   \*\*<https://myproject.domain.com/abc123**\\>
   then your Audience URI will be the following.

```
https://myproject.domain.com/abc123/saml/metadata
```

6. Ensure the **Name ID** format is set to **EmailAddress**
7. Ensure the **Application username** is set to **Email**

![](/files/gG1X0pBi1QdGLHb7RdK9)

The **Attribute Statements** and **Group Attribute Statements** section is where we can define the name for different User Information (attributes) and define the name for SAML Groups. This will ensure the required information is provided by the SAML user when they authenticate.

8. Set the following for the **Attribute Statements**

<table><thead><tr><th width="193">Name</th><th width="151">Format</th><th>Value</th></tr></thead><tbody><tr><td>email</td><td>Basic</td><td>user.email</td></tr><tr><td>firstName</td><td>Basic</td><td>user.firstName</td></tr><tr><td>lastName</td><td>Basic</td><td>user.lastName</td></tr></tbody></table>

8. Set the following for the **Group Attribute Statements**\
   Ensure the Matchest regex filter is set to: `.*`

<table><thead><tr><th width="187">Name</th><th width="151">Format</th><th>Filter</th></tr></thead><tbody><tr><td>groups</td><td>Unspecified</td><td>Matches regex: <code>.*</code></td></tr></tbody></table>

![](/files/0RrJo6ijfNiRm1lxe3iv)

9. Click **Next** to complete the configuration of your Okta SAML 2.0 application.

### Create Users

With the application configured, create a user base within the Okta Admin dashboard. These Users can then be assigned to a SAML group which will be associated with the SAML Application and allow for mapping between SAML Groups and Form.io roles.

1. Within your Okta Admin dashboard, click the **Directory** tab and select **People**

![](/files/1z26gagAOWkxcXxPxMVF)

2. Within the People tab, click the **Add** **Person** button
3. Enter person **details** for the SAML User
4. Click the **Password** dropdown to determine how Users password will be set
5. Click **Save** to add the User

<figure><img src="/files/tkM8cP6Y3UM48GbZ0h78" alt="" width="521"><figcaption></figcaption></figure>

### Create & Assign Groups

With our Users in place, the next step is to create **Groups** the SAML Users will be assigned to. This will allow us to establish mappings between SAML Groups and Form.io roles.

1. Within your Okta Admin dashboard, click the **Directory** tab and select **Groups**
2. Click the **Add Group** button

![](/files/TFTLVW7UDXF3ZNRbvg3s)

3. Give your Group a **Name** and click **Save**

<img src="/files/iIZxZ0oQsap5kTW8puSp" alt="" width="520">

With a Group created, the next step is to assign users to the Group.

4. From the **Group** tab, select the Group to add Users to
5. Click the **Assign people** button

<figure><img src="/files/IOhC4brdLiqtCVCRDuo8" alt="" width="563"><figcaption></figcaption></figure>

6. Click the **+** button next to a User to assign them to a Group

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

#### **Assign Groups To SAML Application**

7. To assign the Group, open the **Directory** tab, select the **Group,** and click the **Applications** tab

<figure><img src="/files/rYvRMQiIwZDlfJonejdH" alt="" width="563"><figcaption></figcaption></figure>

8. Click the **Assign applications** button
9. Within the modal window, click the **Assign** button next to your **SAML application**

<figure><img src="/files/YaJVE32qYrenCehWjyE7" alt="" width="465"><figcaption></figcaption></figure>

### Passport Configuration

Once the SAML application setup is finalized, XML data will be extracted from the application and utilized for building the Passport Configuration. This JSON configuration will be saved to the Form.io Project to complete the integration.

{% hint style="info" %}
[**Click Here**](#saml-passport-config) for more information about SAML Passport Configurations
{% endhint %}

1. Within the Okta Admin Dashboard, click the **Application** tab and select your SAML app
2. Click the **Sign On** tab and copy the **Metadata URL**
3. Copy the **Metadata URL** and open the URL within your browser

<figure><img src="/files/2Wj2pedj7T18zIRnprp6" alt="" width="560"><figcaption></figcaption></figure>

4. Store the XML information as it will be used to construct the **Passport Config**

<figure><img src="/files/QCqMesqlqQcN5lc2eIqt" alt="" width="563"><figcaption></figcaption></figure>

5. Construct the **Passport Config JSON** object. Search the XML file for the property names within the example below and input the data accordingly.
   * The **identityProviderUrl** and **entryPoint** endpoints can be found by searching **SingleSignOnService**
   * The **cert** can be found by searching the **X509Certificate**
   * The **identifierFormat** can be found by searching **NameIDFormat** (emailAddress endpoint)
   * The **issuer** can be found by searching the **entityID**
   * The **audience** must match the **Audience Restriction** endpoint within the **General** tab of your Okta SAML application.

{% hint style="info" %}
Quickly generate the JSON object by utilizing the [**SAML Passport Generator**](#saml-passport-generator) found within the SAML Settings of the Form.io Project.
{% endhint %}

Example Template:

<pre><code><strong>{"identityProviderUrl": "https://trial-3793339.okta.com/app/trial-3793339_formiossoauthentication_1/abc123/sso/saml",
</strong>  "entryPoint": "https://trial-3793339.okta.com/app/trial-3793339_formiossoauthentication_1/abc123/sso/saml",
  "cert": "abc123",
  "identifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
  "issuer": "http://www.okta.com/abc123",
  "audience": "https://yourdomain.com/myproject/saml/metadata"}
</code></pre>

### Form.io Integration

With the Passport Config JSON object constructed, the Form.io project can now be configured.

1. Within the Form.io Project, click **Settings** > **Authentication** > **SAML**
2. Click the **Authorization Settings** tab

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

3. Scroll down and paste the **Passport Config** JSON from the previous step

<figure><img src="/files/2OlnISK43BoIpsxWsAkF" alt="" width="563"><figcaption></figcaption></figure>

4. Click the **Configuration** tab and add the following to the **Email Path** setting field\
   `email`
5. **Save** your settings

#### **Role Mapping**

In many cases, you may want to map the SAML Role associated with the SAML User to a Form.io Role. Apply the following configurations to configure the Role mappings.

6. Within the Form.io SAML settings, click the Configuration tab and set the following to the **Role Path**\
   [`groups`](#user-content-fn-1)[^1]

<figure><img src="/files/9MEJVoqti9dSTdjm8HrL" alt=""><figcaption></figcaption></figure>

7. Within your **Okta** **SAML Application,** click the **Assignments** tab and click **Groups**.\
   Take note of the **Group** **Names** assigned to the application.

<figure><img src="/files/0VqXPsSdi7wIrJtgFOv1" alt="" width="542"><figcaption></figcaption></figure>

8. Back to the Form.io SAML settings, scroll down to the **Role Mapping** setting
9. Map **Okta** **SAML** **Groups** (case sensitive) to the desired **Form.io Roles**
10. **Save** your settings

<figure><img src="/files/PsiJ2j8YWP81sQN4rZ0W" alt="" width="508"><figcaption></figcaption></figure>

After authentication, SAML users assigned to the **Admin** SAML role will obtain the Form.io **Administrator** role, while those assigned to the **Member** role will receive the Form.io **Authenticated** role. This can be seen by inspecting the user object within the dev console.

<figure><img src="/files/2suCzha2BgRqoyNV2x0S" alt=""><figcaption></figcaption></figure>

#### **Authentication Configuration**

The final step is to configure the Form.io Login form embedded in your application to support SAML. Alternatively, you can modify your application to support a similar process. Follow the link below for documentation.

[**Form.io Authentication Configuration**](#form.io-authentication-configuration)

## Microsoft Entra ID

This section covers the [**Microsoft Entra ID**](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id) SAML application setup process and integration with the Form.io Project.

{% hint style="info" %}
The UI and theming may differ slightly between the free plan and paid plan
{% endhint %}

### Create and Configure Application

1. After setting up your account, navigate to the [**Azure Portal**](https://portal.azure.com/), click the left navigation panel, and select **Microsoft Entra ID**.

![Azure AD Portal](/files/vhgH7ov1KbM3skb5qhMf)

2. Within the left-hand navigation bar, select **Enterprise Applications**

![Enterprise Applications](/files/o2d68f4DlrbeKBC2ZRya)

3. Click the **+New Application** button

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

4. Search and select **Entra SAML Toolkit**

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

5. Give the **Application** a name and click the **Create** button

<figure><img src="/files/MYK3S2SAlOb7iCOk5sHj" alt="" width="544"><figcaption></figcaption></figure>

6. Within the Entra ID application, click the **Single sign-on** button in the **Manage** toolbar
7. Select the **SAML** option

   <figure><img src="/files/c8rtnWQUMFpiwXAlASXh" alt=""><figcaption></figcaption></figure>
8. Within the application **Set up** section, scroll down and copy the **Microsoft Entra Identifier** endpoint. Save this ID for later.

<figure><img src="/files/h06B7atG7RKYAw7KI8sX" alt="" width="563"><figcaption></figcaption></figure>

9. Scroll back up to the **Basic SAML Configuration** section and click the **Edit** button

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

10. Apply the following **SAML Configuration** for the Application

* Click the **Add Identifier** button and input the **Identifier (Entity ID)** - Microsoft Entra Identifier copied in the previous step\
  `https://sts.windows.net/abc-123-def-456`
* Add the **Reply URL** (Assertion Consumer Service URL) - [**Live Endpoint** ](https://help.form.io/admin/projects/project-ui#header)of the Form.io Project application with form.io/saml/acs appended at the end of the URL.\
  `https://myproject.domain.com/abc123/saml/acs`
* Add the **Sign On URL** - Application domain endpoint\
  `https://myapplication.domain.com`
* **Save** the settings

<img src="/files/MFLep0ySqxqDd7Ywzz9p" alt="Edit Basic Information" width="563">

11. Within the **Single sign-on** of your application, click the **Edit** button for the **SAML Certificates**

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

12. Set **Signing Option** to **Sign SAML response and assertion**
13. Set **Signing Algorithm** to **SHA-256**
14. Click the **Save** button

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

### Create Users

With the application configured, we can now add Users that will authenticate against Entra ID.

1. Return to the **Entra ID Portal**
2. Within the left-hand navigation bar, click the **Manage** tab and then **Users**

{% hint style="info" %}
Ensure you [**assign Microsoft License**](https://learn.microsoft.com/en-us/entra/fundamentals/license-users-groups) to users or groups within Entra ID
{% endhint %}

2. Click the **+New User** button

<div align="left"><img src="/files/gZ3sVkohev3IjzQk1aq4" alt="users"></div>

3. Input the User information and click **Review + create** button
4. Select how the **User** **Password** should be set

{% hint style="warning" %}
Ensure the User **email address** and **name** is set within the **Properties** tab of the user profile

Contact your Azure administrator if these properties are not available
{% endhint %}

<figure><img src="/files/xfLUaNWF1CcYJ3QDTCAv" alt="" width="491"><figcaption></figcaption></figure>

5. Click the **Create** button after reviewing the User information
6. Create several other users to test Group and Role mapping detailed in the next section.

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

### Create & Assign Groups

With our Users in place, the next step is to create **Groups** the Entra ID Users will be assigned to. This will allow us to establish mappings between SAML Groups (Roles) and Form.io roles.

1. Click the **Groups** tab and **All Groups** within the left-hand navigation bar.

{% hint style="info" %}
Ensure you a [**assign Microfosft License**](https://learn.microsoft.com/en-us/entra/fundamentals/license-users-groups) to users or groups within Entra ID
{% endhint %}

2. Click the **+New Group** button

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

3. Give the Group a **Group Name** and keep the remaining settings at their default values

<figure><img src="/files/VX4CRi4q8y5EjOANNqYj" alt="" width="521"><figcaption></figcaption></figure>

4. Click the the **Create** button
5. Return to the main Group page and click the **Group** we just created

<figure><img src="/files/POO9LvOltxmylZdHMigo" alt="" width="563"><figcaption></figcaption></figure>

6. Expand the **Manage** tab and click **Members**
7. Click the **+Add members** button

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

6. **Search** for the User created in the previous section
7. Tick the **checkbox** next to the members you wish to add
8. Click the **Select** button at the bottom of the page

<figure><img src="/files/gAg4bVVOmjBqCGlwkna3" alt="" width="563"><figcaption></figcaption></figure>

9. Follow the same steps to create additional Groups

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

#### **Enable Group Claims**

With the Groups established, the next step is to enable the Group claim within the Entra ID application.

1. Navigate back to your **Entra ID SAML** application
2. Click the **Single sign-on** tab
3. Edit the **Attributes & Claims** section

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

4. Click the **+Add a group claim** button

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

5. Select the **Groups assigned to the application** option
6. Click the **Source attribute** dropdown and select the **Cloud-only group display names** option
7. **Save** the claim

<figure><img src="/files/gtH58TlA2YHndq3kmM8N" alt="" width="443"><figcaption></figcaption></figure>

8. Within the Attributes & Claim page, take note of the **Group Claim** endpoint\
   `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups`

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

#### **Assigning Groups to Application**

1. Navigate back to your **Entra ID SAML** application
2. Select the **Assign users and groups** tab then click the **+ Add user/group** button
3. On the next screen, click the **None Selected**

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

4. Tick the checkbox next to the **Groups** you wish to assign to the application
5. Click the **Select** button at the bottom of the screen and then **Assign** on the following page

<figure><img src="/files/8HFQhmG6rvI5VDT1U9H0" alt="" width="563"><figcaption></figcaption></figure>

After assigning the Groups, you should see the Groups displayed within the User and Groups tab of the Entra ID application. Users assigned to the selected groups will be associated with the Entra ID Application.

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

### Passport Configuration

Once the SAML application setup is finalized, XML data will be extracted from the application and utilized for building the Passport Configuration. This JSON configuration will be saved to the Form.io Project to complete the integration.

{% hint style="info" %}
[**Click Here**](#saml-passport-config) for more information about SAML Passport Configurations
{% endhint %}

#### **Download XML File**

1. Navigate to your **Entra ID SAML** application
2. Click the **Single sign-on** tab
3. Within the **SAML Certificates** click the **download** button for the **Federation Metadata XML**

<figure><img src="/files/WI999aAKfcSqHDDLFJDw" alt="" width="563"><figcaption></figcaption></figure>

4. Store the XML information as it will be used to construct the **Passport Config**

<figure><img src="/files/GcYBBrsE2Ynw07YfLFiK" alt="" width="563"><figcaption></figcaption></figure>

5. Construct the **Passport Config JSON** object by locating the parameter titles in the XML file as shown in the example below, and input your specific data accordingly

```
{"identityProviderUrl": "https://login.microsoftonline.com/abc-123-def-456/saml2",
  "entryPoint": "https://login.microsoftonline.com/abc-123-def-456/saml2",
  "logoutUrl": "https://login.microsoftonline.com/abc-123-def-456/saml2",
  "cert": "abc123def567",
  "issuer": "https://sts.windows.net/1234-9f02-4c3a-abd-1234/",
  "callbackUrl": "https://app.domain.com/form.io/saml/acs",
  "signatureAlgorithm": "sha256"}
```

* The **identityProviderUrl**, **entryPoint**, and **logoutUrl** endpoint can be found by searching the **SingleSignOnService**
* The **cert** can be found by searching the **X509Certificate**
* The **issuer** can be found by searching the **entityID**
* The **callbackUrl** must match the **Reply URL** endpoint within the **Single sign-on** tab of your Entra ID application
* The **signatureAlgorithm** will be set to **sha256**

{% hint style="info" %}
Quickly generate the JSON object by utilizing the [**SAML Passport Generator**](#saml-passport-generator) found within the SAML Settings of the Form.io Project.
{% endhint %}

### Form.io Integration

With the Passport Config JSON object constructed, the Form.io project can now be configured.

1. Within the Form.io Project, click **Settings** > **Authentication** > **SAML**
2. Click the **Authorization Settings** tab

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

3. Scroll down and paste the **Passport Config** JSON from the previous step

<figure><img src="/files/Yp1Oi2w6aOGTRlagDFDm" alt="" width="563"><figcaption></figcaption></figure>

4. Click the **Configuration** tab and add the following to the **Email Path** setting field\
   `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name`
5. Save your **Settings**

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

#### **Role Mapping**

In many cases, you may want to map the SAML Role associated with the SAML User to a Form.io Role. Apply the following configurations to configure the Role mappings.

6. Within the Form.io SAML settings, click the Configuration tab and set the following to the **Role Path**\
   `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups`

<figure><img src="/files/UlNTcnUiyvahHpWMEOXg" alt="" width="500"><figcaption></figcaption></figure>

7. Back to your **Entra ID** **SAML Application,** click the **Users and group** tab. Take note of the **Group** **Names** assigned to the application.

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

8. Back to the Form.io SAML settings, scroll down to the **Role Mapping** setting
9. Map **SAML** **Roles** (case sensitive) to the desired **Form.io Roles**
10. **Save** your settings

<figure><img src="/files/y333qlRTahPM01sMuOVu" alt="" width="508"><figcaption></figcaption></figure>

After authentication, SAML users assigned to the **Admin** SAML role will obtain the Form.io **Administrator** role, while those assigned to the **Member** role will receive the Form.io **Authenticated** role. This can be seen by inspecting the user object within the dev console.

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

#### **Authentication Configuration**

The final step is to configure the Form.io Login form embedded in your application to support SAML. Alternatively, you can modify your application to support a similar process. Follow the link below for documentation.

[**Form.io Authentication Configuration**](#form.io-authentication-configuration)

## AuthO

This section covers the [**Auth0 Provider**](https://auth0.com/docs/authenticate/protocols/saml/saml-configuration) SAML application setup process and integration with the Form.io Project.

### Create and Configure Application

1. From your Auth0 Admin dashboard, create a new Auth0 by clicking the **Applications** tab and clicking the **+Create Application** button

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

2. From the application Modal window, select **Single Page Web Applications**

<figure><img src="/files/rmQer3iHVvsAYomO4FDt" alt="" width="563"><figcaption></figcaption></figure>

3. Provide a **name** for the Application and click the **Create** button
4. Click the **Addons** tab
5. Toggle the **SAML 2.0** button

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

6. Click the **Settings** tab
   * Within the Modal window, provide the **Allowed Callback URL.**\
     Also known as the [**ACS** **endpoint**](#user-content-fn-2)[^2] by other SAML providers.\
     For this value, copy your Form.io project endpoint and append **/saml/acs** at the end of the URL.\
     \
     \&#xNAN;*Example*: if your project API endpoint is\
     \*\*<https://yourdomain.com/myproject**,\\>
     then your Assertion Consumer Service URL will be the following.\
     `https://yourdomain.com/myproject/saml/acs`

<figure><img src="/files/U6aPoLQrnp0L6UaF3vgc" alt="" width="468"><figcaption></figcaption></figure>

* Scroll down and click the **Enable** button
* After enabling the application, click **Save**

<figure><img src="/files/ExwRLb8TgQMAxDNeaz4j" alt="" width="480"><figcaption></figcaption></figure>

The application should now be ready for SAML Authentication. The next step is to create Groups the SAML users will be assigned to. These Groups will then be mapped to Form.io roles for granular permissions.

### Create Users

With the application configured, create a user base within the Auth0 Admin dashboard. These Users can then be assigned to a SAML group which will be associated with the SAML Application and allow for mapping between SAML Groups and Form.io roles.

1. Within the Auth0 admin dashboard, click the **User Management** tab and then **Users**

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

2. Click the **+Create User** button

<figure><img src="/files/B9xWrmbMVzEd40YfEtXK" alt="" width="563"><figcaption></figcaption></figure>

3. Input user information and click **Create**

<img src="/files/gpy43zAomuKcc6hCQNWj" alt="" width="488">

4. Create additional users to assign to the different Roles that will be established in the next step.

<figure><img src="/files/4i3GhcpE65UoVVGBxsSb" alt=""><figcaption></figcaption></figure>

### Create & Assign Groups

With our Users in place, the next step is to create **Groups** the SAML Users will be assigned to. Auth0 groups are created and managed through extensions. This group extension will allow us to establish mappings between SAML groups and Form.io roles for granular permissions.

1. Within the left-hand navigation bar, click **Extensions**
2. Select **Auth0 Authorization**

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

3. Click **Install** within the Extension modal

<figure><img src="/files/bD54DwaT76x4yhK0AfOF" alt="" width="563"><figcaption></figcaption></figure>

4. Once installed, click the **Extension** and **Authorize** the extension for your application
5. Click the **GO TO CONFIGURATION** button

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

6. Click the **Groups** radio button
7. Click the **Publish Rule** button

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

8. Within the Extension, click the **Groups** tab then **+ Create Your First Group** button

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

9. Give the Group a **Name** and **Description**

<figure><img src="/files/A6kZ0cb0MHoFrdaGdCjQ" alt="" width="488"><figcaption></figcaption></figure>

10. Click the **+Add Member** button

<figure><img src="/files/LtP3YkgRL17dDjvmemxS" alt="" width="563"><figcaption></figcaption></figure>

11. Search and **select** the **user(s)** to assign to the Group and **Save**

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

### Passport Configuration

Once the SAML application setup is finalized, XML data will be extracted from the application and utilized for building the Passport Configuration. This JSON configuration will be saved to the Form.io Project to complete the integration.

{% hint style="info" %}
[**Click Here**](#saml-passport-config) for more information about SAML Passport Configurations
{% endhint %}

1. Within the Auth0 Admin Dashboard, click the **Application** tab and select your SAML app
2. Click the **Add On** tab and click the **SAML2 Web App**

<figure><img src="/files/K1oCZIH5HxnmMsDDNncG" alt="" width="563"><figcaption></figcaption></figure>

3. Within the **Usage** tab, click the **Download** to extract the XML file

<figure><img src="/files/m98njQNog79tiCNUgBDM" alt="" width="477"><figcaption></figcaption></figure>

4. Store the XML information as it will be used to construct the **Passport Config**

<figure><img src="/files/4F2sACIbQj0jUBSmhu3d" alt="" width="563"><figcaption></figcaption></figure>

5. Construct the **Passport Config JSON** object. Search the XML file for the property titles within the example below and input the data accordingly.
   * The **identityProviderUrl** and **entryPoint** endpoint can be found by searching the **SingleSignOnService** HTTP-REDIRECT endpoint
   * The **cert** can be found by searching the **X509Certificate**
   * The **identifierFormat** can be found by searching **NameIDFormat**
   * The **logoutUrl** endpoint can be found by searching **SingleLogoutService**
   * The **callbackURL** must match the **Application Callback URL** endpoint within the **Setting** tab of your Auth0 SAML application.
   * The **issuer** can be found by searching the **entityID**
   * Set the **wantAuthnResponseSigned** to **false**

{% hint style="info" %}
Quickly generate the JSON object by utilizing the [**SAML Passport Generator**](#saml-passport-generator) found within the SAML Settings of the Form.io Project.
{% endhint %}

```
{"identityProviderUrl": "https://dev-3co66mp5xvfzciov.us.auth0.com/samlp/abc123", 
"entryPoint": "https://dev-3co66mp5xvfzciov.us.auth0.com/samlp/abc123", 
"cert": "abc123def456", 
"identifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", 
"callbackUrl": "http://localhost:3000/ipajzfemjjsisnv/saml/acs",
"issuer": "urn:dev-abc123.us.auth0.com",
"wantAuthnResponseSigned": false}
```

### Form.io Integration

With the Passport Config JSON object constructed, the Form.io project can now be configured.

1. Within the Form.io Project, click **Settings** > **Authentication** > **SAML**
2. Click the **Authorization Settings** tab

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

3. Scroll down and paste the **Passport Config** JSON from the previous step

<figure><img src="/files/KckpQkNufztcOQpMxv5t" alt="" width="563"><figcaption></figcaption></figure>

4. Click the **Configuration** tab and add the following to the **Email Path** setting field\
   `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name`
5. **Save** your settings

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

#### **Role Mapping**

In many cases, you may want to map the SAML Role associated with the SAML User to a Form.io Role. Apply the following configurations to configure the Role mappings.

6. Within the Form.io SAML settings, click the Configuration tab and set the following to the **Role Path**\
   `http://schemas.xmlsoap.org/claims/Group`

<figure><img src="/files/UDBh2UxUDCuD3IH5D43A" alt="" width="539"><figcaption></figcaption></figure>

7. Within your **Auth0** **SAML application,** click the **Extensions** tab, and the **Auth0 Authorization** extension.
8. Click the **Groups** tab and take note of the **Groups** **Names** assigned to the extension.

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

9. Back to the Form.io SAML settings, scroll down to the **Role Mapping** setting
10. Map **SAML** **Roles Names** (case sensitive) to the desired **Form.io Roles**
11. **Save** your settings

<figure><img src="/files/PsiJ2j8YWP81sQN4rZ0W" alt="" width="508"><figcaption></figcaption></figure>

After authentication, SAML users assigned to the **Admin** SAML role will obtain the Form.io **Administrator** role, while those assigned to the **Member** role will receive the Form.io **Authenticated** role. This can be seen by inspecting the user object within the dev console.

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

#### **Authentication Configuration**

The final step is to configure the Form.io Login form embedded in your application to support SAML. Alternatively, you can modify your application to support a similar process. Follow the link below for documentation.

[**Form.io Authentication Configuration**](#form.io-authentication-configuration)

## Form.io Authentication Configuration

SAML Authentication can be set up either by utilizing a Form.io Login form or by modifying the code within your application

### **Login Form Configuration**

Follow the steps below to achieve SAML SSO authentication using a Form.io Login form.

1. Edit the authentication Form embedded within your application
2. Drag and drop a **Button** component
3. Modify the **Label** to reflect SAML authentication
4. Click the **Action** dropdown and select **Custom**
5. Copy the following code and paste it into the **Button Custom Logic** code block

```javascript
Formio.ssoInit('saml');
```

![](/files/Par9CwHQjB4JF9x6Nyqd)

6. Add a **Hidden** component
7. Click the **Data** tab and open the **Custom Default Value** tab
8. Add the following **JavaScript** within the code block
9. **Save** the Settings and Form

```javascript
if (Formio.pageQuery().saml) {
  Formio.ssoInit('saml');
  window.location.replace('/');
}
```

![](/files/-MblvS4vYF6Lmyg3Ts4C)

### Application Configuration

To achieve authentication within your application, the following code will instigate the SSO process.

```javascript
import { Formio } from '@formio/js';
Formio.ssoInit('saml');
```

The `Formio.ssoInit` method is used to both instigate the SSO process as well as handle the callback once the authentication occurs. Because of this, it may be beneficial to place this code within a button on so that the login will occur once you click on a "Login" button, and then trigger the `Formio.ssoInit` method once the page returns with the `?saml=` query parameter (which indicates that the SSO process has completed).

```javascript
<button class="btn btn-primary" role="button" onclick="Formio.ssoInit('saml')">Login</button>
<script type="text/javascript">  
  // Check to see if the saml query is provided.
  if (Formio.pageQuery().saml) {
    // Perform the login.
    Formio.ssoInit('saml');
    
    // Navigate to the homepage after they login.
    window.location.replace('/');
  }
</script>
```

## SAML Passport Configuration

The "Passport Config" setting simplifies the process of configuring SAML authentication settings for your Form.io project, allowing you to specify how your application interacts with the SAML identity provider using JSON configuration. Passport then utilizes this configuration to manage the authentication flow and grant access to authenticated users

{% hint style="info" %}
Form.io utilizes the Node.js SAML Authentication library.\
[**Click Here** ](https://github.com/node-saml/node-saml)for documentation and a full list of SAML Passport properties
{% endhint %}

As an example, many Microsoft Azure Active Directory deployments do not cryptographically sign their SAML assertions (despite signing the top-level SAML response). Form.io, however, expects both the SAML response and the SAML assertions to be signed by default. In this case, your Passport Config JSON object would set the `wantAssertionsSigned` parameter to false, and might look something like this:

```
{
  "identityProviderUrl": "<identity provider URL>"
  "entryPoint": "<entry point URL>",
  "logoutUrl": "<logout url>",
  "cert": "<cert>",
  "issuer": "<issuer url>",
  "audience" "<audience url>",
  "wantAssertionsSigned": false
}
```

This JSON configuration will ensure that Form.io is aware that it should not expect the assertions to be cryptographically signed.

{% hint style="info" %}
For those customers that use private key encryption for SAML responses and/or a private key for decryption, we provide two environment variables which allows you to provide the absolute paths to those key files in your container's file system rather than as plain text string values in the Passport Config JSON object. Those variables are SAML\_PASSPORT\_PRIVATE\_KEY\_PATH and SAML\_PASSPORT\_DECRYPTION\_PVK\_PATH. Alternatively, you can specify the private key and/or the decryption private key as strings in the JSON object.
{% endhint %}

### SAML Passport Generator

Quickly generate the Passport JSON object by utilizing the SAML Passport Generator found within the SAML Settings of the Form.io Project. This generator allows the user to simply input the required endpoints and credentials from the XML data of the SAML provider. The generator will then output the correct JSON structure for the user saving time and relieving potential user error.

To access the Passport Generator, navigate to the SAML settings page:

**Settings** > **Authorization** > **SAML** > **Authorization Settings**

{% embed url="<https://youtu.be/MXW6dUw5A2s>" %}

Scroll down to the Passport Configuration of the settings page. Here you can select different SAML Properties required by the SAML provider. Once selected, input the correlated endpoint or settings from the XML file of your SAML provider.

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

A full JSON object will be generated and passed to the Passport configuration which will be used to authenticate and authorize SAML users.

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

### Custom Parser

The Custom Parser generates a custom payload for the JWT token based on the SAML Profile object of the authenticating SAML user. This feature opens up additional SAML Profile attributes and claims within the user object as well as more granular control over SAML/Form.io role mappings.

{% hint style="info" %}
The API Server will first check if there is data saved to the "Custom Parser" tab before generating a token. If the Custom Parser is being utilized, then the filled Profile Fields are not taken into account when generating the JWT token.

The Project ID within the payload can not be changed.
{% endhint %}

#### Custom Parser Example

This example will include additional profile claims saved to the SAML Profile object as well as the

```javascript
user = {
  _id: profile.id,
  data: {
    id: profile.id,
    roles: profile.roles,
    email: profile.email,
    name: 'Joe Smith'
  },
  roles: [
    'ROLE_ID_1',
    'ROLE_ID_2'
  ]
}
```

*Profile* – the data from the SAML profile object.

*Roles* - These are the IDs of the project roles you would like this user to have when authenticating.

### Test Connection to SAML - Coming Soon <a href="#test-connection-to-saml" id="test-connection-to-saml"></a>

After the XML Metadata or Passport Config is filled in, you can use a test connection to SAML. Сlick on the *"Save SAML Authorization Settings and Connect to SAML"* button, and all unsaved authorization SAML settings will be saved and a new window will open with a test connection to the SAML provider.

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

After successful authorization, the authorized user's profile object will be available. This will make it easier to fill in the Profile Fields or use Custom Parser.

<figure><img src="/files/Hm4hjlIc39vhsvIRuQaE" alt="" width="563"><figcaption></figcaption></figure>

[^1]: This value is referencing the SAML group parameter configured within the application

[^2]: The ACS URL is an *endpoint on the service provider where the identity provider will redirect to with its* authentication response


# Resource Based Authentication

## User Accounts

One of the most unique concepts of Form.io is how Users are defined and utilized. While other platforms have distinct User entities, and are managed within their own API and Database namespaces; Form.io is different in that a User is actually a Submission within a Resource form. This enables any Resource to establish the structure of a User account and support multiple types of user models within your application. This becomes very useful if your data management application needs to keep track of multiple User models as well as manage the different ways in which users can be assigned access to other forms and submission data.

For example, if you were creating a Patient Onboarding application, several resources can be used to define the different user models that would be used, such as.

* **Patient** - This would be a resource that would include fields that would define a clinic patient such as First Name, Last Name, Patient ID, etc.
* **Physician** - This would be a resource that would include the fields that would define a clinic physician such as Specialty, Physician ID, etc.
* **Admin** - This resource could be used to define any Clinic administrators that need to help the Physicians manage the patient records.

Since Users are simply *Submissions* within a form, they contain all the same elements as any other submission within any Form. The primary difference between a User submission and any other Submission within Form.io is that a User submission will almost always take advantage of a property on the Submission model called "roles". This property is used to define all of the **Roles** that a user has within a project and is defined in the following section. A typical user submission looks like the following.

```javascript
{
    "_id": "5ffe1a78bf0654a91f191b2e",
    "data": {
        "email": "bob@example.com",
        "firstName": "Bob",
        "lastName": "Smith"
    },
    "owner": "5e5411ba1e29ee1aab5031d9",
    "roles": [
        "5e5411c11e29ee5fca5031e8",
        "5ffe1a2cbf06545768191b0a"
    ],
    "metadata": {
        "timezone": "America/Chicago",
        "offset": -360,
        "origin": "https://remote.form.io",
        "referrer": "",
        "browserName": "Netscape",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Safari/537.36",
        "pathName": "/",
        "onLine": true,
        "login": {
            "attempts": 0,
            "last": 1610488618123
        }
    },
    "form": "5e5411c11e29eef4885031ea",
    "project": "5e5411c11e29eeb3015031e6",
    "externalIds": [],
    "created": "2021-01-12T21:54:00.403Z",
    "modified": "2021-01-12T21:54:00.412Z"
}
```

{% hint style="info" %}
Due to security constraints, roles within a user can ONLY be added through a **Role Assignment** action. It is not possible to update a submission to "add" roles to a submission via POST, PUT, or PATCH requests. They can, however, be removed from a submission via these API methods.
{% endhint %}

## Session Management

The Form.io platform ensures that every authentication within the platform is associated with a current "session". A Session is a mechanism to connect authenticated requests made by the same JWT token, and also ensures that "sessions" can be invalidated once a login occurs. This works by adding a Session ID to a JWT Token ID to each token provided to a user. This can be seen by copying your JWT Token from your localStorage (usually found within the **formioToken** variable) into jwt.io, which will give you the following.

```javascript
{
  "user": {
    "_id": "5e5411ba1e29ee1aab5031d9"
  },
  "iss": "https://api.mysite.com:3000",
  "sub": "5e5411ba1e29ee1aab5031d9",
  "jti": "5fffbb5646d76c292a7b5df1",
  "iat": 1610595158,
  "exp": 1610609558
}
```

The `jti` property is your current Session ID, and will change if you logout and re-login.

Once a user logs out of their account, by hitting the logout API, the current session will become invalid, and all outstanding JWT tokens that use that session ID will no longer be able to be used. The user must first login again, which will re-establish a new session, and then that JWT token can be utilized to make API calls into the Form.io platform.

The Session Management system is used as an added security measure to enforce that JWT tokens cannot be used again once a user has logged out of their account. This also protects the situation where if any user is using multiple devices and logs out of one device, their session will also be logged out of all other devices.

## Login and Registration

Once a user resource has been established, a project can now be configured to allow a user to login or register within a project. This is accomplished by creating a **Login** form and **Registration** form respectively.

### Creating a Login Form

A login form for a user is usually created by default within a project, but it is important to understand what it is there to accomplish and how to create your own for any other users you wish to have Login to a Form.io project. Any login form can be created by creating a new Form and building that form as you would like to display it within your application. For example, your login form may look like the following.

![A typical user login form](/files/xNOU0lW3btzLanOynxOU)

Now that you have a login form created, the next thing that needs to occur is that you will need to add a **Login Action** to the form. This can be done by navigating to the Actions, and then select **Login** action, and then select **Add Action.** Next, you will configure the Resources you would like to search when performing the Login account search. Considering that any Resource can be defined as a "user", this allows you to search multiple resources to perform a login through a single form. You will also want to map the fields within the form that are defined as the **Username Field** and the **Password Field** as follows.

![Defining the Login resources](/files/HaCPe5nDXZzqxwfqoP65)

Next, click **Save** to save this action.

Next, we will want to remove the default **Save Submission** action since for a Login process, it does not make much sense to "save" the submission being made to that form.

{% hint style="info" %}
In some situations, you may actually want to keep the Save Submission action attached to the Login form. This is a good way to keep an audit log of everyone who has logged into your system.
{% endhint %}

Now that you have a **Login** action attached to the form, and the **Save Submission** action removed, the last thing that needs to be configured for a Login form is to allow **Anonymous** users the ability to submit the form (since users will be anonymous when this form is submitted). This can be configured within the Access section of your form, where you will add **Anonymous** to the **Create Own** permission as follows.

####

![Anonymous role added to Create Own Submissions allows anonymous submission.](/files/9mGNHoIf9VcIvGqbUZA9)

Now that we have our Login form configured, we can either embed the form within the application, or by submitting a POST request to the submission endpoint of this form API. For example, if this form endpoint is configured as "user/login", we can login using the following API.

```javascript
POST: https://forms.mysite.com/myproject/user/login/submission
```

### Creating a Registration Form

A Registration form is identical to a Login form with one difference, the **Save Submission** action. Within a Registration form, you will always want to Save the submission of the registration, which can be configured by adding this action to your form in the actions tab. Once you add a new Save Submission action, the next thing you will need to ensure is that you are saving the record to the correct resource for the registration process. This is done within the configuration of the Save Submission action, where you can select which resource you would like to save the submission to, and then perform a field map so that the correct fields from the registration are passed along to the underlying resource as shown below.

![Registrations save the submission to the underlying resource.](/files/-MblvS4vYF6Lmyg3Ts4C)

Assuming that your registration form has the URL path of "user/register", you can now embed this within your application, or you can register a new user into your project using the following API command.

```javascript
POST: https://forms.mysite.com/myproject/user/register/submission
```


# Two Factor Authentication

Using 2FA with Formio Resource-based authentication

{% hint style="warning" %}
The following Two-Factor Authentication workflow is only compatible with Form.io Resource-based authentication. It's very common to utilize other authentication methods like OIDC or SAML for the deployed developer portal or custom applications. Please refer to the authentication provider's documentation to set up 2FA with these alternative methods.
{% endhint %}

In addition to providing full authentication capabilities, **\<form.io>** also provides a very robust method for Automatic Logins via Email. There are many use cases where Email Login is utilized including, but not limited to…

* Email Registrations (where they must click on a link in their email to register)
* Email Reset Password

{% hint style="info" %}
[**Click Here** ](/how/sso-email-token)for a walkthrough on how to integrate an SSO Email Token to authenticate your application user base using Form.io.
{% endhint %}

To make this happen, there is a special token that can be added to the message of your email action and templates. This token will generate a special JWT token to log in the person who the email was addressed to. This token is defined as follows.

```
  [[token(data.email=user)]]
```

Which is defined as follows…

```
  [[token(LOOKUP_FIELD=LOOKUP_RESOURCE)]]
```

* **LOOKUP\_FIELD** - This is the field that is used to search for the record we wish to login. This works by taking the value provided in the Email To: Address and searching the resource with that value as that field.
* **LOOKUP\_RESOURCE** - This is the resource to lookup when establishing the token.

***Important Note*** - This will ONLY create a token if the persons email address that is being sent the email is found within the resource.

For example, lets say you have a Resource as ***Customer*** and a field within that resource called ***Email*** you wish to create a token for. Now lets say you wish to send an email to one of your customers to complete their registration via email. This may look like the following.

```
  To:      john@example.com
  From:    no-reply@form.io
  Subject: Register Now
  Message: Click here to complete your registration http://myapp.com/?token=[[token(data.email=customer)]]#register
```

This following email performs the following:

* Looks up **data.email=<john@example.com>** within the **customer** Resource.
* If a record is found, it generates a temporary token and replaces `[[token(data.email=customer)]]` with that token.
* Tells the application to navigate to the ***#register*** state once the authentication has been performed.

This turns this email into something that looks like the following.

```
  To:      john@example.com
  From:    no-reply@form.io
  Subject: Register Now
  Message: Click here to complete your registration http://myapp.com/?token=lkjsdlkjs90980982l3kjlkjslkjsd....#register
```

#### Application Changes to handle Email Tokens <a href="#application-changes-to-handle-email-tokens" id="application-changes-to-handle-email-tokens"></a>

Once you have the email being sent, this single sign on URL will direct them to the Serverless application which needs to handle the token. This requires a minor change within your application to accept the token and then reset the `localStorage` value with the new token. The **\<form.io>** library will then take it from there and authenticate all future requests with that token. You can make this change by adding the following to your ***/app/config.js*** file.

```javascript
// Parse query string
var query = {};
location.search.substr(1).split("&").forEach(function(item) {
  query[item.split("=")[0]] = item.split("=")[1] && decodeURIComponent(item.split("=")[1]);
});

// This is what you will need to add to your application.
if (query.token) {
  localStorage.setItem('formioToken', query.token);
  localStorage.removeItem('formioAppUser');
  localStorage.removeItem('formioUser');
  window.history.pushState("", "", location.pathname + location.hash);
}
```

Once you have implemented this, your application should then be able to handle an automatic email authentication into your application.


# Form.io E-Sign+

Describes Form.io E-Sign+, a digital signature module.

## Introduction

Form.io E-Sign+ is an enterprise-level digital signature module that enables the capture and verification of cryptographically secure signatures associated with submission data — all within your own environment and without relying on external signature services.

E-Sign+, as a digital signature tool, is designed to confirm that the signed piece of data and its context (the form, custom properties, etc.) have not changed since it was signed.

Key aspects of the E-Sign+ solution provided by Form.io:

* **Zero-trust.** It exists entirely within the app, in your environment; you don't have to trust 3rd-party providers with your digital signatures. The digital signatures are stored in your database.
* **API-driven**. You can access any signed data/form via API, using its native submission ID.
* **Decoupled from PDFs**. E-Sign+ lets you take an immutable snapshot of data within your app without relying on PDFs (but still export to PDF if you need).
* **Full control on E-Sign+ private key.** Signature data is stored in the database as a token signed with the private key provided by you. You can store your keys outside of the deployment (e.g. using AWS KMS) or set it as the Form.io enterprise server environment variable.
* Sign using **any field type, any context**. Any input field can be used as a signature: checkbox, email, signature, text field and so on. Your signature can sign the whole form data or just a part of it.
* **Customize the E-Sign+ stamp.** Use your custom templates for the E-Sign+ stamp.

## Licensing

{% hint style="info" %}
The E-Sign+ module is only available for self-hosted environments that have both Security Compliance Module and E-Sign+ enabled within their license configuration.\
\
Contact **<sales@form.io>** to acquire a License.
{% endhint %}

After E-Sign+ is enabled for the license key, the Signatures tab is available under the **Signatures** section in the navigation bar of any form.

<figure><img src="/files/sSpdv9gRWRjnt1cG5MDA" alt=""><figcaption><p>Digital Signature tab</p></figcaption></figure>

## Enabling E-Sign+

E-Sign+ configuration is available after the form has the following settings enabled:

1. Submission Revisions
2. Form Revisions set to 'Use original form revisions when viewing submissions'.

## E-Sign+ Settings

<figure><img src="/files/4T97aIcHMzsuqj3CsJTQ" alt=""><figcaption><p>Digital Signature Settings</p></figcaption></figure>

To implement digital signatures in a form, first decide what form components will be used as signatures in the form. Different components can serve as a digital signature. To set a component as a digital signature:

1. Add the component(s) to the form.
2. Click **Add Digital Signature** to attach digital signature functionality to the desired components. A form can have one or more components that serve as digital signatures.

### **Digital Signature Component Settings**

When a component is set to be a digital signature, the following settings are configurable:

<figure><img src="/files/mmCkbUeKJKrJYYylcC9O" alt=""><figcaption><p>Digital Signature Component Settings</p></figcaption></figure>

* **Digital Signature Component** - The form component that will be used as a signature.\
  The following components are selectable as the Digital Signature Component when present in a form:

<table data-full-width="false"><thead><tr><th>Basic</th><th width="149">Advanced</th><th width="112.9796142578125">Layout*</th><th>Data*</th><th>Premium</th></tr></thead><tbody><tr><td>Text Field</td><td>Email</td><td></td><td>Container <sub>(child field)</sub></td><td>Data Source</td></tr><tr><td>Text Area</td><td>URL</td><td></td><td></td><td>File</td></tr><tr><td>Number</td><td>Phone Number</td><td></td><td></td><td></td></tr><tr><td>Password</td><td>Tags</td><td></td><td></td><td></td></tr><tr><td>Checkbox</td><td>Date &#x26; Time</td><td></td><td></td><td></td></tr><tr><td>Select Box</td><td>Day</td><td></td><td></td><td></td></tr><tr><td>Select (Must use HTML5)</td><td>Time</td><td></td><td></td><td></td></tr><tr><td>Radio</td><td>Currency</td><td></td><td></td><td></td></tr><tr><td></td><td>Survey</td><td></td><td></td><td></td></tr><tr><td></td><td>Signature</td><td></td><td></td><td></td></tr></tbody></table>

{% hint style="info" %}
**Layout** and **Data** components cannot serve as the signature component; only the compatible fields within them can be selected.
{% endhint %}

* **Digital Signature Data** - Select the form components on which the data will be confirmed by the Digital Signature. If the signed value of these fields changes, the digital signature becomes invalid and the data is expected to sign again.
* **Include all form data in Digital Signature** - When this setting is enabled, the Digital Signature will be responsible for all form data. If the value of some form component is changed, the digital signature will be invalid and the data is expected to sign again.
* **Submission properties to include in Digital Signatures** - A comma separated path to the data inside the submission object that will be used for the digital signature verification.\
  This setting selects the submission properties (except for submission data) that will invalidate the digital signature when they are changed.
* **Enable editing of submission data within Digital Signatures** - By default, the signed data is disabled in the UI to protect it from modifications. Enable this setting to leave signed data enabled.
* The **Templates** settings sets the default template of the digital signature stamp and tooltip.

## Templates

The Templates settings enables users to customize UI for digital signature stamps and tooltips using the JavaScript [Lodash](https://lodash.com/docs/4.17.15#template) library.

Several variables are available inside templates:

| Variable            | Description                                                                                                  |
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
| esign               | The form.io Digital Signature object                                                                         |
| esignTooltip        | The markup of the Digital Signature tooltip represented as a string (available only for the stamp template). |
| esignInvalidMessage | The default message for invalid Digital Signature (available only for the stamp template).                   |
| esignIconClass      | The class of the Digital Signature default stamp icon (available only for the stamp template).               |
| pdfForm             | Indicates whether the current form has a PDF display type.                                                   |
| form                | The complete form JSON object                                                                                |
| submission          | The complete submission object.                                                                              |
| data                | The complete submission data object.                                                                         |
| row                 | Contextual "row" data, used within DataGrid, EditGrid, and Container components                              |
| component           | The current component JSON                                                                                   |
| instance            | The current component instance.                                                                              |
| value               | The current value of the component.                                                                          |
| moment              | The moment.js library for date manipulation.                                                                 |
| \_                  | An instance of [Lodash](https://lodash.com/docs/).                                                           |
| utils               | An instance of the [FormioUtils](/dev/javascript-development/javascript-utilities) object.                   |
| util                | An alias for "utils".                                                                                        |

#### esign object

The *esign* variable is available in both stamp and tooltip templates and contains main information about the Digital Signature.

The *esign* object typically has the following properties:

* *created* - the ISO formatted date of Digital Sigature creation;
* *valid* - if Digital Signature is valid it has a true value, if not - the massage why Digital Signature is not valid;
* *\_id* - Digital Signature ID;
* *\_sid* - ID of the submission that contains this Digital Signature;
* *signature* - the object with Digital Signature data that has the following properties:
  * *compPath* - path to Digital Signature component inside the form JSON;
  * *valuePath* - path to the value of the Digital Signature component in submission data;
  * *user* - the id and email of the user who signs the Digital Signature field;
  * *submission* - the submission revision object (without submission data) created together with Digital Signature.

### Digital Signature Stamp Template

Example of a custom stamp template:

```html
{% if (esign.valid === true) { %}
<span class="formio-esign-stamp">
  <i ref="esignTooltip" style="cursor:pointer" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}' aria-hidden='true'></i>
  <span class="formio-esign-stamp-description">
    Signed on {{new Date(esign.created).toLocaleString()}}
  </span>
</span>
{% } %}
{% if (esign.valid !== true) { %}
<span class="formio-esign-stamp formio-esign-stamp-invalid formio-esign-stamp-description">
  <i ref="esignTooltip" style="cursor:pointer" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}' aria-hidden='true'></i>
  Invalid Digital Signature
</span>
{% } %}
```

***Tips**:*

* To use a tooltip with your Digital Signature stamp, add the following attributes to some HTML element inside the stamp template:\
  \&#xNAN;*`ref="esignTooltip" data-tooltip="{{esignTooltip}}.`*

An example of this attribute inserted in a HTML is:

```html
 <i ref="esignTooltip" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}'></i>< ref="esignTooltip" style="cursor:poer" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}' aria-hidden='true'></i>
```

* To use a different stamp template for the form and printed PDF (when viewing the submission as a PDF), check if *instance.options.pdf* is true:

```html
{% if (instance.options.pdf) { %}
 // stamp template for printed PDF
{% } %}
{% if (!instance.options.pdf) { %}
 // stamp template for the form
{% } %}
```

* To use different stamp template to differntiate between valid and invalid Digital Signatures, check if *esign.valid* is equal to true or not:

```html
{% if (esign.valid === true) { %}
 // stamp template for valid eSignature
{% } %}
{% if (esign.valid !== true) { %}
 // stamp template for invalid eSignatrue
{% } %}
```

### Digital Signature Tooltip Template

The following code snippet provides an example of a custom tooltip template:

```html
<div class="formio-esign-tooltip">
  <span class="{{esign.valid !== true ? 'formio-esign-tooltip-header-invalid' : ''}} formio-esign-tooltip-header">
    <span>eSignature</span>
    <span class="formio-esign-tooltip-status" >{{esign.valid !== true ? 'invalid' : 'verified'}}</span>
  </span>
  <ul class="formio-esign-tooltip-info">
    <li class="formio-esign-tooltip-info-item"><span class="formio-esign-tooltip-info-item-title">ID:</span><<span>{{esign?._id || '-'}}</span></li>
    <li class="formio-esign-tooltip-info-item"><span class="formio-esign-tooltip-info-item-title">Path:</span><span>{{esign?.signature?.valuePath || '-'}}</span></li>
  </ul>
</div>

```

## E-Sign+ Cryptography

E-Sign+ uses asymmetric cryptographic keys to sign and verify a snapshot of the data. The required key is supplied by the form builder.

There are 2 ways to provide keys for E-Sign+ cryptographic operations:

* Set `ESIGN_PRIVATE_KEY_FILE` variable for the form.io server deployment. This variable accepts a file path to your private key (e.g., `ESIGN_PRIVATE_KEY_FILE=/user/stuff/mykey.txt`).;
* Add integration with third-party key management service (e.g. AWS KMS).

### ESIGN\_PRIVATE\_KEY\_FILE server variable

The simplest way to provide keys for a digital signature is to set the following environment variables in your **formio/formio-enterprise** deployment:

* `FORMIO_FEATURE_ESIGNATURE=true` — enables the E-Sign+ module.
* `ESIGN_PRIVATE_KEY_FILE` — set to the file path of your private key (e.g., `ESIGN_PRIVATE_KEY_FILE=/user/stuff/mykey.txt`).

It is not recommended to set the public key as an environment variable, as it can be easily extracted from the private key.

{% hint style="info" %}
Check the deployment documentation to know more about environment variables:

[https://help.form.io/deployments/deployment-guide/enterprise-server](https://help.form.io/deploy/enterprise-server)
{% endhint %}

Requirements for a private key set to ESIGN\_PRIVATE\_KEY\_FILE:

* Key type: RSA
* Key size: 2048-bit
* Public key:
  * type: 'spki'
  * format - 'pem';
* Private key:
  * type - 'pkcs8'
  * format - 'pem'

An example of RSA2048 key generation using the *node*:*crypto* module:

```javascript
    const crypto = require('crypto');

    const { privateKey } = crypto.generateKeyPair(
      'rsa',
      {
        modulusLength: 2048,
        publicKeyEncoding: {
          type: 'spki',
          format: 'pem',
        },
        privateKeyEncoding: {
          type: 'pkcs8',
          format: 'pem',
        },
      }
    );
```

### Integration with Key Management Services (KMS)

To use a third party provider to store and manage keys, add E-Sign+ integration settings on the project level.

#### AWS KMS

The E-Sign+ module can use AWS KMS API to sign and verify the digital signature data.

To begin by creating an RSA2048 key available for 'sign and verify' operations in AWS KMS:

1. Log in to your AWS account;
2. Open **Services > Security, Identity, & Compliance > Key Management Service**
3. Click on the **Create a key** button on the main AWS KMS page\
   or\
   Select **Customer managed keys** on the left-hand sidebar, then click on the **Create a key** button on the top of the keys list:

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

5. Follow the key setup wizard to create your key.\
   The step 1 key settings should resemble the following:

<figure><img src="/files/bpvPMUM7wmojTk7CK2EJ" alt=""><figcaption><p>AWS KMS Key - step 1</p></figcaption></figure>

6. In the **Customer managed keys** list, open the key that was just created from the key list section and copy the Key ID:

<figure><img src="/files/U6b90MAyZUdc42GK8xcV" alt=""><figcaption><p>Key Settings</p></figcaption></figure>

7. Create an Access Key for your AWS account, and copy the Access Key ID and Secret Key.\
   Check AWS documentation to create the access key for your account:

<https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html>

Next, add AWS KMS integration settings to the Form.io project settings through the Developer Portal:

1. Open the intended project on the Form.io Developer Portal.
2. Open the project's **Settings,** and click **Digital Signature.**
3. Add the AWS KMS settings:

<figure><img src="/files/k7AfUfRh2OlaPr1GSEru" alt=""><figcaption><p>AWS KMS Integration Settings</p></figcaption></figure>

4. **Save** the project settings.

From this point, the AWS KMS API will be used for the Digital Signature cryptographic operations for this project.

## Digital Signature Examples

Create a new form and add components as shown in the example below:

<figure><img src="/files/LmtD12RMjkziQCPuawfY" alt=""><figcaption><p>Example Form</p></figcaption></figure>

This form is expected to have 3 signatures:

* The signature of the purchase initiator, who is to fill in fields 1-3 and sign this data by adding the name in field 4.
* The signature of the head of department, who approves the purchase in field 5.
* The signature of the accountant who fills in the budget field and confirms it by adding a signature in field 7.

#### Configure the example digital signature:

Once the form described above has been created, configure the form settings as follows:

1. Enable submission revisions and original form revisions for the form:

<figure><img src="/files/MkNco4oGVtwNXouGmxJg" alt=""><figcaption><p>Revisions configuration</p></figcaption></figure>

2. From the toolbar, go to **Sign.** Click the **Add Digital Signature** button and configure Digital Signature for Field 4:

<figure><img src="/files/D7ufPPVZhRqZOZOgJFYm" alt=""><figcaption><p>Digital Signature config for field 4</p></figcaption></figure>

3. Click **Save**.
4. Repeat these steps to add Digital Signatures for Field 5 and Field 7, being sure to save them:

<figure><img src="/files/oeLlkzlsfCP44sBOq58n" alt=""><figcaption><p>Digital Signature config for field 5 and 7</p></figcaption></figure>

4. Save the Digital Signature settings by clicking on **Save Settings.**

<figure><img src="/files/dyoPTbgPIzw9P2Cke5Lq" alt=""><figcaption><p>Save Settings</p></figcaption></figure>

To see the Digital Signatures in action:

1. Go to the **Use** tab, fill in fields 1-4 and submit the form.
2. Go tot he **Data** tab and open the submission that was just made.

When viewing/editing this submission, note that the green digital signature stamp is displayed under field 4. This stamp confirms that the digital signature was created, and that neither the Digital Signature data (fields 1-4) nor the form have been changed since it was signed.\
\
Hovering the cursor above the signature stamp reveals the signature metadata.

<figure><img src="/files/rAgvX2tHLNwNvcRCttwX" alt=""><figcaption><p>Field 4 Digital Signature</p></figcaption></figure>

<figure><img src="/files/N1stnIghLfXLwuWmC2Lw" alt=""><figcaption><p>DigitalDigital Signature on hover</p></figcaption></figure>

3. Edit the submission. Note that fields 1-4, protected by the signature, are disabled.
4. Fill in field 5 and **Submit** the form. Note that a digital signature is created for field 5.
5. Fill in fields 6 and 7, then **Submit** the form. Note that digital signatures are created for all signature fields:

<figure><img src="/files/zzKzVnQvl8GNy8qlD4OW" alt=""><figcaption><p>Signed Form</p></figcaption></figure>

#### **Digital signature validation when editing of submission data within Digital Signatures is enabled**

When the signed fields are not disabled from modification, digital signature data is validated on the client side. If some signed value is changed, digital signature becomes invalid and the signature field is cleared. That means the changed data is must be signed again.

To see this in action:

1. Follow steps 1-2 from the previous example.
2. Open Digital Signature settings and enable **Enable editing of submission data within Digital Signatures.**\
   Click the **Save Settings** button to save this change.
3. Sign the form following steps 3-5 from the previous example.\
   Note that signed fields are not disabled and can be edited.
4. Edit the submission and change the quantity field from 1 to 2.\
   As a consequence, the Digital Signatures for fields 4 and 5 become invalid and signature values are reset.

<figure><img src="/files/EVbo9FUfCGWiOBNpVXCq" alt=""><figcaption><p>Invalid Digital Signatures</p></figcaption></figure>

<figure><img src="/files/0zHg7i8QCQKrotBTX66R" alt=""><figcaption><p>Invalid Digital Signature on hover</p></figcaption></figure>

The digital signature for Field 7 is still valid, as it is only responsible for the data in field 6.\
If there is a change to Field 6, the Field 7 value will be cleared and the Digital Signature will become invalid. These fields will need to be signed again and new Digital Signatures will be created for the form.

## Digital signature and PDF

### PDF-First Form

Digital signatures with PDF-first forms function in the same way as with web forms.

### PDF View of Webform Submissions

The PDF of the webform submission on a form that contains digital signatures will display a digital signature stamp on any signed fields.

## Render digital signatures in an application

Use **@formio/esignature** module to render digital signatures in an application by completing the following steps:

1. Use one of the following terminal commands to install the **@formio/esignature** module into your application:

```
npm i --save @formio/esignature
```

or

```
yarn add @formio/esignature
```

2. Connect the E-Sign+ module in your application:

```javascript
import {Formio} from '@formio/js';
import esignature from '@formio/esignature';

Formio.use(esignature);

```

3. Import the digital signature module styles in your application:

```javascript
import '@formio/esignature/esignature.css';
```


# Integrations


# e-Sign+

## Introduction

Form.io E-Sign+ is an enterprise-level digital signature module that enables the capture and verification of cryptographically secure signatures associated with submission data — all within your own environment and without relying on external signature services.

E-Sign+, as a digital signature tool, is designed to confirm that the signed piece of data and its context (the form, custom properties, etc.) have not changed since it was signed.

Key aspects of the E-Sign+ solution provided by Form.io:

* **Zero-trust.** It exists entirely within the app, in your environment; you don't have to trust 3rd-party providers with your digital signatures. The digital signatures are stored in your database.
* **API-driven**. You can access any signed data/form via API, using its native submission ID.
* **Decoupled from PDFs**. E-Sign+ lets you take an immutable snapshot of data within your app without relying on PDFs (but still export to PDF if you need).
* **Full control on E-Sign+ private key.** Signature data is stored in the database as a token signed with the private key provided by you. You can store your keys outside of the deployment (e.g. using AWS KMS) or set it as the Form.io enterprise server environment variable.
* Sign using **any field type, any context**. Any input field can be used as a signature: checkbox, email, signature, text field and so on. Your signature can sign the whole form data or just a part of it.
* **Customize the E-Sign+ stamp.** Use your custom templates for the E-Sign+ stamp.

## Licensing

{% hint style="info" %}
The E-Sign+ module is only available for self-hosted environments that have both Security Compliance Module and E-Sign+ enabled within their license configuration.\
\
Contact **<sales@form.io>** to acquire a License.
{% endhint %}

After E-Sign+ is enabled for the license key, the Signatures tab is available under the **Signatures** section in the navigation bar of any form.

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

## Enabling E-Sign+

E-Sign+ configuration is available after the form has the following settings enabled:

1. Submission Revisions
2. Form Revisions set to 'Use original form revisions when viewing submissions'.

## E-Sign+ Settings

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

To implement digital signatures in a form, first decide what form components will be used as signatures in the form. Different components can serve as a digital signature. To set a component as a digital signature:

1. Add the component(s) to the form.
2. Click **Add Digital Signature** to attach digital signature functionality to the desired components. A form can have one or more components that serve as digital signatures.

### **Digital Signature Component Settings**

When a component is set to be a digital signature, the following settings are configurable:

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

* **Digital Signature Component** - The form component that will be used as a signature.\
  The following components are selectable as the Digital Signature Component when present in a form:

<table data-full-width="false"><thead><tr><th>Basic</th><th width="149">Advanced</th><th width="112.9796142578125">Layout*</th><th>Data*</th><th>Premium</th></tr></thead><tbody><tr><td>Text Field</td><td>Email</td><td></td><td>Container <sub>(child field)</sub></td><td>Data Source</td></tr><tr><td>Text Area</td><td>URL</td><td></td><td></td><td>File</td></tr><tr><td>Number</td><td>Phone Number</td><td></td><td></td><td></td></tr><tr><td>Password</td><td>Tags</td><td></td><td></td><td></td></tr><tr><td>Checkbox</td><td>Date &#x26; Time</td><td></td><td></td><td></td></tr><tr><td>Select Box</td><td>Day</td><td></td><td></td><td></td></tr><tr><td>Select (Must use HTML5)</td><td>Time</td><td></td><td></td><td></td></tr><tr><td>Radio</td><td>Currency</td><td></td><td></td><td></td></tr><tr><td></td><td>Survey</td><td></td><td></td><td></td></tr><tr><td></td><td>Signature</td><td></td><td></td><td></td></tr></tbody></table>

{% hint style="info" %}
**Layout** and **Data** components cannot serve as the signature component; only the compatible fields within them can be selected.
{% endhint %}

* **Digital Signature Data** - Select the form components on which the data will be confirmed by the Digital Signature. If the signed value of these fields changes, the digital signature becomes invalid and the data is expected to sign again.
* **Include all form data in Digital Signature** - When this setting is enabled, the Digital Signature will be responsible for all form data. If the value of some form component is changed, the digital signature will be invalid and the data is expected to sign again.
* **Submission properties to include in Digital Signatures** - A comma separated path to the data inside the submission object that will be used for the digital signature verification.\
  This setting selects the submission properties (except for submission data) that will invalidate the digital signature when they are changed.
* **Enable editing of submission data within Digital Signatures** - By default, the signed data is disabled in the UI to protect it from modifications. Enable this setting to leave signed data enabled.
* The **Templates** settings sets the default template of the digital signature stamp and tooltip.

## Templates

The Templates settings enables users to customize UI for digital signature stamps and tooltips using the JavaScript [Lodash](https://lodash.com/docs/4.17.15#template) library.

Several variables are available inside templates:

| Variable            | Description                                                                                                  |
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
| esign               | The form.io Digital Signature object                                                                         |
| esignTooltip        | The markup of the Digital Signature tooltip represented as a string (available only for the stamp template). |
| esignInvalidMessage | The default message for invalid Digital Signature (available only for the stamp template).                   |
| esignIconClass      | The class of the Digital Signature default stamp icon (available only for the stamp template).               |
| pdfForm             | Indicates whether the current form has a PDF display type.                                                   |
| form                | The complete form JSON object                                                                                |
| submission          | The complete submission object.                                                                              |
| data                | The complete submission data object.                                                                         |
| row                 | Contextual "row" data, used within DataGrid, EditGrid, and Container components                              |
| component           | The current component JSON                                                                                   |
| instance            | The current component instance.                                                                              |
| value               | The current value of the component.                                                                          |
| moment              | The moment.js library for date manipulation.                                                                 |
| \_                  | An instance of [Lodash](https://lodash.com/docs/).                                                           |
| utils               | An instance of the [FormioUtils](/dev/javascript-development/javascript-utilities) object.                   |
| util                | An alias for "utils".                                                                                        |

#### esign object

The *esign* variable is available in both stamp and tooltip templates and contains main information about the Digital Signature.

The *esign* object typically has the following properties:

* *created* - the ISO formatted date of Digital Sigature creation;
* *valid* - if Digital Signature is valid it has a true value, if not - the massage why Digital Signature is not valid;
* *\_id* - Digital Signature ID;
* *\_sid* - ID of the submission that contains this Digital Signature;
* *signature* - the object with Digital Signature data that has the following properties:
  * *compPath* - path to Digital Signature component inside the form JSON;
  * *valuePath* - path to the value of the Digital Signature component in submission data;
  * *user* - the id and email of the user who signs the Digital Signature field;
  * *submission* - the submission revision object (without submission data) created together with Digital Signature.

### Digital Signature Stamp Template

Example of a custom stamp template:

```html
{% if (esign.valid === true) { %}
<span class="formio-esign-stamp">
  <i ref="esignTooltip" style="cursor:pointer" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}' aria-hidden='true'></i>
  <span class="formio-esign-stamp-description">
    Signed on {{new Date(esign.created).toLocaleString()}}
  </span>
</span>
{% } %}
{% if (esign.valid !== true) { %}
<span class="formio-esign-stamp formio-esign-stamp-invalid formio-esign-stamp-description">
  <i ref="esignTooltip" style="cursor:pointer" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}' aria-hidden='true'></i>
  Invalid Digital Signature
</span>
{% } %}
```

***Tips**:*

* To use a tooltip with your Digital Signature stamp, add the following attributes to some HTML element inside the stamp template:\
  \&#xNAN;*`ref="esignTooltip" data-tooltip="{{esignTooltip}}.`*

An example of this attribute inserted in a HTML is:

```html
 <i ref="esignTooltip" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}'></i>< ref="esignTooltip" style="cursor:poer" data-tooltip="{{esignTooltip}}" class='{{esignIconClass}}' aria-hidden='true'></i>
```

* To use a different stamp template for the form and printed PDF (when viewing the submission as a PDF), check if *instance.options.pdf* is true:

```html
{% if (instance.options.pdf) { %}
 // stamp template for printed PDF
{% } %}
{% if (!instance.options.pdf) { %}
 // stamp template for the form
{% } %}
```

* To use different stamp template to differntiate between valid and invalid Digital Signatures, check if *esign.valid* is equal to true or not:

```html
{% if (esign.valid === true) { %}
 // stamp template for valid eSignature
{% } %}
{% if (esign.valid !== true) { %}
 // stamp template for invalid eSignatrue
{% } %}
```

### Digital Signature Tooltip Template

The following code snippet provides an example of a custom tooltip template:

```html
<div class="formio-esign-tooltip">
  <span class="{{esign.valid !== true ? 'formio-esign-tooltip-header-invalid' : ''}} formio-esign-tooltip-header">
    <span>eSignature</span>
    <span class="formio-esign-tooltip-status" >{{esign.valid !== true ? 'invalid' : 'verified'}}</span>
  </span>
  <ul class="formio-esign-tooltip-info">
    <li class="formio-esign-tooltip-info-item"><span class="formio-esign-tooltip-info-item-title">ID:</span><<span>{{esign?._id || '-'}}</span></li>
    <li class="formio-esign-tooltip-info-item"><span class="formio-esign-tooltip-info-item-title">Path:</span><span>{{esign?.signature?.valuePath || '-'}}</span></li>
  </ul>
</div>

```

## E-Sign+ Cryptography

E-Sign+ uses asymmetric cryptographic keys to sign and verify a snapshot of the data. The required key is supplied by the form builder.

There are 2 ways to provide keys for E-Sign+ cryptographic operations:

* Set `ESIGN_PRIVATE_KEY_FILE` variable for the form.io server deployment. This variable accepts a file path to your private key (e.g., `ESIGN_PRIVATE_KEY_FILE=/user/stuff/mykey.txt`).;
* Add integration with third-party key management service (e.g. AWS KMS).

### ESIGN\_PRIVATE\_KEY\_FILE server variable

The simplest way to provide keys for a digital signature is to set the following environment variables in your **formio/formio-enterprise** deployment:

* `FORMIO_FEATURE_ESIGNATURE=true` — enables the E-Sign+ module.
* `ESIGN_PRIVATE_KEY_FILE` — set to the file path of your private key (e.g., `ESIGN_PRIVATE_KEY_FILE=/user/stuff/mykey.txt`).

It is not recommended to set the public key as an environment variable, as it can be easily extracted from the private key.

{% hint style="info" %}
Check the deployment documentation to know more about environment variables:

[https://help.form.io/deployments/deployment-guide/enterprise-server](https://help.form.io/deploy/enterprise-server)
{% endhint %}

Requirements for a private key set to ESIGN\_PRIVATE\_KEY\_FILE:

* Key type: RSA
* Key size: 2048-bit
* Public key:
  * type: 'spki'
  * format - 'pem';
* Private key:
  * type - 'pkcs8'
  * format - 'pem'

An example of RSA2048 key generation using the *node*:*crypto* module:

```javascript
    const crypto = require('crypto');

    const { privateKey } = crypto.generateKeyPair(
      'rsa',
      {
        modulusLength: 2048,
        publicKeyEncoding: {
          type: 'spki',
          format: 'pem',
        },
        privateKeyEncoding: {
          type: 'pkcs8',
          format: 'pem',
        },
      }
    );
```

### Integration with Key Management Services (KMS)

To use a third party provider to store and manage keys, add E-Sign+ integration settings on the project level.

#### AWS KMS

The E-Sign+ module can use AWS KMS API to sign and verify the digital signature data.

To begin by creating an RSA2048 key available for 'sign and verify' operations in AWS KMS:

1. Log in to your AWS account;
2. Open **Services > Security, Identity, & Compliance > Key Management Service**
3. Click on the **Create a key** button on the main AWS KMS page\
   or\
   Select **Customer managed keys** on the left-hand sidebar, then click on the **Create a key** button on the top of the keys list:

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

1. Follow the key setup wizard to create your key.\
   The step 1 key settings should resemble the following:

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

2. In the **Customer managed keys** list, open the key that was just created from the key list section and copy the Key ID:

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

3. Create an Access Key for your AWS account, and copy the Access Key ID and Secret Key.\
   Check AWS documentation to create the access key for your account:

<https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html>

Next, add AWS KMS integration settings to the Form.io project settings through the Developer Portal:

4. Open the intended project on the Form.io Developer Portal.
5. Open the project's **Settings,** and click **Digital Signature.**
6. Add the AWS KMS settings:

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

7. **Save** the project settings.

From this point, the AWS KMS API will be used for the Digital Signature cryptographic operations for this project.

## Digital Signature Examples

Create a new form and add components as shown in the example below:

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

This form is expected to have 3 signatures:

* The signature of the purchase initiator, who is to fill in fields 1-3 and sign this data by adding the name in field 4.
* The signature of the head of department, who approves the purchase in field 5.
* The signature of the accountant who fills in the budget field and confirms it by adding a signature in field 7.

#### Configure the example digital signature:

Once the form described above has been created, configure the form settings as follows:

1. Enable submission revisions and original form revisions for the form:

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

2. From the toolbar, go to **Sign.** Click the **Add Digital Signature** button and configure Digital Signature for Field 4:

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

3. Click **Save**.
4. Repeat these steps to add Digital Signatures for Field 5 and Field 7, being sure to save them:

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

5. Save the Digital Signature settings by clicking on **Save Settings.**

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

To see the Digital Signatures in action:

6. Go to the **Use** tab, fill in fields 1-4 and submit the form.
7. Go tot he **Data** tab and open the submission that was just made.

When viewing/editing this submission, note that the green digital signature stamp is displayed under field 4. This stamp confirms that the digital signature was created, and that neither the Digital Signature data (fields 1-4) nor the form have been changed since it was signed.\
\
Hovering the cursor above the signature stamp reveals the signature metadata.

<figure><img src="/files/e46tAdVSY1KCNSPrBfy7" alt=""><figcaption><p>Field 4 Digital Signature</p></figcaption></figure>

<figure><img src="/files/IxBqEuUoeqv752IMVwK2" alt=""><figcaption><p>Digital Signature on hover</p></figcaption></figure>

8. Edit the submission. Note that fields 1-4, protected by the signature, are disabled.
9. Fill in field 5 and **Submit** the form. Note that a digital signature is created for field 5.
10. Fill in fields 6 and 7, then **Submit** the form. Note that digital signatures are created for all signature fields:

<figure><img src="/files/RHi1ZhbDmALvvhW0J4KP" alt=""><figcaption><p>Signed form</p></figcaption></figure>

#### **Digital signature validation when editing of submission data within Digital Signatures is enabled**

When the signed fields are not disabled from modification, digital signature data is validated on the client side. If some signed value is changed, digital signature becomes invalid and the signature field is cleared. That means the changed data is must be signed again.

To see this in action:

1. Follow steps 1-2 from the previous example.
2. Open Digital Signature settings and enable **Enable editing of submission data within Digital Signatures.**\
   Click the **Save Settings** button to save this change.
3. Sign the form following steps 3-5 from the previous example.\
   Note that signed fields are not disabled and can be edited.
4. Edit the submission and change the quantity field from 1 to 2.\
   As a consequence, the Digital Signatures for fields 4 and 5 become invalid and signature values are reset.

<figure><img src="/files/t33FMk4qR0Ap3AkVZPQK" alt=""><figcaption><p>Invalid Digital Signature</p></figcaption></figure>

<figure><img src="/files/7IXGynSpztDwBbLa13IN" alt=""><figcaption><p>Invalid Digital Signature on hover</p></figcaption></figure>

The digital signature for Field 7 is still valid, as it is only responsible for the data in field 6.\
If there is a change to Field 6, the Field 7 value will be cleared and the Digital Signature will become invalid. These fields will need to be signed again and new Digital Signatures will be created for the form.

## Digital signature and PDF

### PDF-First Form

Digital signatures with PDF-first forms function in the same way as with web forms.

### PDF View of Webform Submissions

The PDF of the webform submission on a form that contains digital signatures will display a digital signature stamp on any signed fields.

## Render digital signatures in an application

Use **@formio/esignature** module to render digital signatures in an application by completing the following steps:

1. Use one of the following terminal commands to install the **@formio/esignature** module into your application:

```
npm i --save @formio/esignature
```

or

```
yarn add @formio/esignature
```

2. Connect the E-Sign+ module in your application:

```javascript
import {Formio} from '@formio/js';
import esignature from '@formio/esignature';

Formio.use(esignature);

```

3. Import the digital signature module styles in your application:

```javascript
import '@formio/esignature/esignature.css';
```


# e-Sign Integrations

## Overview

Form.io allows integration with eSignature providers to capture an eSignature, a digital signature, from one or multiple signers. This process is customizable and works for both PDF and API forms.

{% hint style="warning" %}
The Form.io **Box Sign** Integration will soon be deprecated
{% endhint %}

## How to use

### Signature Component

To add an eSignature component, drag and drop a Signature component onto a form as seen below:

![Drag and drop the Signature component onto a form](/files/4Q2HUVkmluH6QmN5jBmC)

Once placed, the Signature component edit modal opens. Click on the "Providers" tab to select a supported eSignature provider. The available options are:

* Default - This is a standard digital signature that should be signed upon form submission
* Box Sign

{% hint style="warning" %}
The Form.io **Box Sign** Integration will soon be deprecated
{% endhint %}

![](/files/izj3Ix4nZ29hB1wjjjCY)

When selecting a provider other than Default, additional fields are available:

* **Signer Email** - The email address of the person needing to provide a signature. This can be a string email address or an interpolated value. For example, in the above screenshot, the value is {{data.emailAddress}}. This assumes there is another component on the form whose display and API value is "Email Address". The value of this component will be substituted for {{data.emailAddress}}.
* **Signer Order** - The order in which this recipient should receive an email request for signature. *Example: any value between 1 and integer max value.*

### eSign Action

Add the eSign action under the Form's "Actions" tab by selecting "eSign (Premium)" from the drop-down on the Actions page as seen below:

![](/files/pBd9abBwPP43H8bVQukT)

The eSign action screen contains several options.

![](/files/OYrnLxB3M7GuIGnCONSr)

The available options include:

* Approvers - Recipients who need to approve a document sent for eSignature, but do not need to provide a signature. The values here can be a string email address or an interpolated value. *Example values: <approver@example.com> or {{data.approverEmailAddress}}*
* Final Signed Copy Recipients - Recipients who need to be sent a copy of the signed document once signing has been completed. The values here can be a string email address or an interpolated value. *Example values: <final_copy_recipient@example.com> or {{data.finalCopyRecipientEmail}}*
* Automatically redirect to E-Sign provider on Form Submit - By checking this box, the form will automatically redirect to the eSignature provider website upon form submission to allow the person submitting the form to provide a signature. Note that there is no redirect back to Form.io upon signature completion. You will have to navigate back to Form.io.

![](/files/GN38g4GZtxh5i581meJX)

* Email Subject - A custom email subject to be included in the signature request email. Valid values are string values. *Example: Please eSign this form*
* Email Message - A custom email message to be included in the signature request email. Valid values are string values. *Example: This is my test email message*
* Name of upload PDF File - The name you wish to customize for the file when uploaded to eSignature provider. Valid values are string values. By default, if you leave this field blank, the name of the file when uploaded to the box will be the submission id. *Example: My request form*

### eSign Integration Settings

Before eSign can be use, set the appropriate eSign integration settings on the project's settings:

![Fill out the eSign integration settings here](/files/Emt1tznOv9RWxUn1BiWo)


# Email Integrations

Form.io allows an easy integration to send emails after any action in the Form. Email Actions are located in the Form Action section but as a requirement it will ask you to use a provider.

{% hint style="info" %}
When using the Form.io SaaS offering @ portal.form.io, **you must set up your own Transport.** The default transport service provided by Form.io is no longer available.Please see more details for setting up an Email Transport below.
{% endhint %}

## SMTP

To setup SMTP settings you need host, port, username and password. (TLS Supported)

For this example we will use MailTrap.io, after the account is created we can proceed to add a new inbox.

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

Then, MailTrap provide the necessary information to setup SMTP. Click in Show Credentials.

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

Next, we can add our credentials to the Email Provider in Form.io Portal Settings. After our information is in place click in Save Project Settings button.

![](/files/coUh0WZEnIBg9Zz8LcZS)

Finally, we can create Email Actions in our forms and choose our transport.

![](/files/pvGPmBwONDxVpgNjno7j)

## Sendgrid

To setup Sendgrid your project will need the API Key of your SendGrid Account

![](/files/rSiiMpFc6iNF1dypvaU0)

Under your Sendgrid Account Settings > API Keys you can create a new API KEY

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

Add a name and choose the API Permission then click in Create & View

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

Copy your API Key and paste it in the Project Settings and click Save Project Settings.

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

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

Finally, we can create Email Actions in our forms and choose our transport.

![](/files/5d8Py7FrTABqNLKiUzLm)

## Mailgun

To setup Mailgun all you need is an API Key and Domain.

![](/files/N5W4hZ4FTbb2BG5l3162)

Finally, we can create Email Actions in our forms and choose our transport.

![](/files/I8taL0YOmxICuoezWNFE)

## Kickbox Validations

To setup Kickbox you can follow these steps.

1. Go to [**https://kickbox.io**](https://kickbox.io/) and create your free account.
2. Click on the **Verify API** section, and then click on **New App**.
3. Give your app a name, then select either **Sandbox** or **Production** and click **Create.**
4. Copy and paste the **API Key** into the following text field.

![](/files/460TuvyGJ60j4gwCYzkZ)

Then, you can add the kickbox validations to your Email Component in your Form.

![](/files/PsQwxG9G9naC4BNKcj4P)


# File Storage

The File component connects the form to a file storage provider and allows the user to upload, view, and manage files. Since **\<form.io>** does not itself store files, we offer a range of 3rd party integrations to meet your File needs.

## Azure Blob

The Azure Blob file upload system allows you to upload files from your hosted forms directly to an Azure Blob storage account. Here are the steps to set up this feature functionality.

**Azure Portal**

Before we begin, you must create or have an existing account within [**Microsoft Azure**](https://portal.azure.com/)

**Create new File Service**

* Once we are in the Azure portal interface, we will want to go click on **Storage Accounts** and add a new storage account.

![](https://no-help.form.io/assets/img/integrations/azure/storage/create-storage.png)

* Next, click on the **Create** button to create the new storage account.
* After this operation has been completed, we will now need to click on that storage account, then click on **Blobs** under the **Blob Service** section, then click **+ Container**.

![](https://no-help.form.io/assets/img/integrations/azure/storage/blob-storage.png)

* Next, create a new Container by clicking on **+Container** and then provide a name for your container.

![](https://no-help.form.io/assets/img/integrations/azure/storage/blob-container.png)

* Next, we will need to ensure that we can upload files from the domain of our application, to do this, we will configure the **CORS** section with the domain where we are hosting our application as well as Form.io portal. To do this, we will click on the CORS section, and configure the Blob Storage cors as follows.

![](https://no-help.form.io/assets/img/integrations/azure/storage/blob-cors.png)

* Now, we will click on **Access Keys** and copy the following credentials for use later.

![](https://no-help.form.io/assets/img/integrations/azure/storage/blob-access-keys.png)

**Enter Azure Project Settings**

* On form.io go to your Project Settings page and Click on **Integrations ❘ File Storage ❘ Azure Blob**
* Enter the information that you copied in the previous configurations as follows.

![](/files/ACoEtP9d2APvCnqMCDMz)

* **Save** your project settings.
* Now for every **File** component that you add to a form, you will need to select the **Azure File Services** Storage dropdown as follows.

![](/files/WQjOvs0ZdFzn7OeJ6R52)

## Custom Url

Custom Url Provider does not have any settings in the Project Settings. Instead, it is set in the *Url* field on the form component when it is added to a form.

In order to use a Custom Url Provider, you will need to set up a service that can upload and serve files.

The information posted to the server will be

```
{
  file: file
}
```

The server should save the contents of the file somewhere and return the following object.

```
{
  url: 'http://link.to/file',
  name: 'The_Name_Of_The_File.doc',
  size: 1000
}
```

You may return additional attributes if desired.

## S3

The S3 Storage provider allows file storage and retrieval using any S3 compatible service but was specifically designed for Amazon Web Services S3.

{% hint style="info" %}
*For an on-premise compatible solution, try seaweedfs. See our* seaweedfs[ ***installation guide***](#seaweedfs)*.*
{% endhint %}

If you haven’t already done so, go to [**Amazon Web Services**](http://aws.amazon.com/) and sign up for an account.

In order to use S3, you will need to configure an IAM user and an S3 bucket.

**Create an IAM user**

* Go to **Services ❘ IAM** and click on the *Users* tab.
* Click the Add User button.
* Enter a user name such as “S3” and then click **Programmatic Access**, then click the **Next** button.

![](https://no-help.form.io/assets/img/integrations/aws/s3/iam-new-user.png)

* Skip the page where you add the user to a group.
* On the last page, press **Create User**
* On the next page, it should show you your access keys. You will need to copy those and add them to a note on your computer which you will need later.

![](https://no-help.form.io/assets/img/integrations/aws/s3/add-user-keys.png)

* Now press **Close** button, which will take you back to the users list.
* Find the user we just created and then click on their name, which will show you their Summary
* Copy the ARN of that user and save it along with your Access Keys from earlier.

![](https://no-help.form.io/assets/img/integrations/aws/s3/copy-arn.png)

* We are now ready to create the **S3** bucket.

**Create an S3 bucket**

* Go to **Services ❘ S3**
* Click + Create Bucket and enter a name and region for the bucket and click **Next**

![](https://no-help.form.io/assets/img/integrations/aws/s3/create-bucket.png)

* Click **Next** for all the other pages of the wizard to complete the creation of the bucket. We can configure all of these options after the bucket is created.
* Click on that bucket which will take you to the bucket page. Click on the **Permissions** tab.

![](https://no-help.form.io/assets/img/integrations/aws/s3/permissions-tab.png)

* Now, click on **Bucket Policy** button and then add the following policy to your bucket.

  ```json
   {
     "Version": "2012-10-17",
     "Statement": [
       {
         "Sid": "UploadFile",
         "Effect": "Allow",
         "Principal": {
           "AWS": "arn:aws:iam::XXXXXX:user/S3"
         },
         "Action": [
           "s3:GetObject",
           "s3:PutObjectAcl",
           "s3:PutObject"
         ],
         "Resource": "arn:aws:s3:::formio-upload/*"
       }
     ]
   }
  ```
* If you wish to have **Public Read** access to your files, then you will need to add the following rule to your policy.

  ```json
   {
      "Sid": "crossdomainAccess",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::formio-upload/crossdomain.xml"
   }
  ```

  So that it looks like the following.

  ```json
   {
      "Version": "2012-10-17",
      "Statement": [
         {
            "Sid": "UploadFile",
            "Effect": "Allow",
            "Principal": {
               "AWS": "arn:aws:iam::XXXXXX:user/S3"
            },
            "Action": [
               "s3:GetObject",
               "s3:PutObjectAcl",
               "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::formio-upload/*"
         },
         {
            "Sid": "crossdomainAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::formio-upload/crossdomain.xml"
         }
      ]
   }
  ```
* **Important Note** You will need to make sure you replace the `arn:aws:iam::XXXXXX:user/S3` with the ARN you copied when you created the user, and also replace the `formio-upload` with the name of your new bucket.
* Next click on **CORS configuration** and add the following.

  ```json
   [
      {
          "AllowedHeaders": [
              "*"
          ],
          "AllowedMethods": [
              "GET",
              "PUT",
              "POST",
              "HEAD",
              "DELETE"
          ],
          "AllowedOrigins": [
              "*"
          ],
          "ExposeHeaders": [],
          "MaxAgeSeconds": 3000
      }
  ]
  ```
* You may replace `"AllowOrigins": ["*"]` with the domain names of the sites your app will be running on or leave it open.
* Make sure you save the configuration and the bucket settings.

**S3 Bucket Encryption (optional)**

Form.io also supports S3 Encryption to provide further safety with the files that are stored within the S3 system. If you wish to enable this feature, you can do so by click on the **Properties** tab, then click on **Default Encryption** and then provide the encryption you would like to use.

![](https://no-help.form.io/assets/img/integrations/aws/s3/s3-encrypt.png)

Your S3 bucket should now be properly configured.

**Enter S3 Project Settings**

* On form.io go to your Project Settings page and Click on **Integrations ❘ File Storage ❘ S3 Storage**
* Enter the information for the IAM user and S3 bucket you just created. Make sure to provide all the necessary configurations that match the setup that you configured. For example, like this.

![](/files/6yKm6fGL56axtuw2EDKJ)

* The following credentials can be provided.

  | Setting             | Description                                                                               | Example                                   |
  | ------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------- |
  | Use MinIO Server    | Check this if you would like to use these settings to connect to a S3 compatible server   |                                           |
  | Access Key ID       | This is the IAM user Access Key ID that you copied when setting up the S3 user.           | ALIAQIQUCRXQ7Q2I8UYQ                      |
  | Secret Access Key   | This is the IAM user Secret Access Key that you copied when setting up the S3 user.       | IykVuiJPYidDhTWyFSfyIOVXuX7tIwIpCC3Sqql/  |
  | Bucket Name         | The name of the bucket you created.                                                       | formio-upload                             |
  | Bucket URL          | If you are using your own S3 compatible server, then provide the url here.                | <https://formio-upload.s3.amazonaws.com/> |
  | Bucket Region       | The region which you setup your Bucket within                                             | us-west-2                                 |
  | Starts With         | This is the top-most folder you wish to place all the files from this project within.     | files/                                    |
  | Access Control List | Determines the Access Control of the files within this bucket.                            | private                                   |
  | S3 Encryption       | The type of encryption you are using for this S3 bucket.                                  | AES-256                                   |
  | KMS Key ID          | Only valid if you are using KMS encryption where you then need to provide your KMS Key ID |                                           |
  | Max Size            | The maximum file size for uploads going into this bucket.                                 | 100MB                                     |
  | Policy Expiration   | The amount of seconds that the Upload policy is valid for                                 | 3600                                      |
* Now make sure to **Save** the project settings.

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

* Now for every **File** component that you add to a form, you will need to select the **S3** Storage dropdown as follows.

### Multipart Upload

AWS S3 offers a Multipart Upload feature that allows users to upload files up to 5TB in size. It can also provide enhanced flexibility when it comes to uploading smaller files. Form.io's File Component supports this feature by letting the form builder opt in to Multipart Upload support on a per form basis.

To use the File Component with Multipart Upload support:

* Ensure that your AWS S3 bucket CORS policy exposes the "ETag" header.
* In the File Component settings, select the checkbox labeled "Use the S3 Multipart Upload API."
* Enter a "part size" in megabytes. The Multipart Upload feature works by "chunking" the file(s) into parts as close to this size as possible. Although this field is required, you can enter your best estimate based on what kinds of files you believe your form users will be uploading. If the file happens to be smaller than the chunk size, Form.io will use a "best-guess" part size to upload the file, so don't worry about being too precise.

## SeaweedFS

{% hint style="info" %}
If the Form.io Platform was deployed to the environment with the [**docker-compose**](/deploy/deployment-overview#docker) methodology, SeaweedFS is already included in the deployment, and manual installation is not required.
{% endhint %}

### Pre-Requisites

To deploy a new SeaweedFS server, complete the following pre-requisite steps:

1. Install [**Docker**](https://docker.io/) either on the local machine, or on a private cloud server.
2. Create the necessary directories to store files using the file browser, or by executing the following commands:

   ```
   mkdir ~/seaweedfs/data
   ```
3. Run the following command to pull the SeaweedFS container from Docker Hub:

   ```
   docker pull chrislusf/seaweedfs
   ```

### **Deploying the SeaweedFS Container**

1. Execute the following command to start the SeaweedFS container:

```bash
docker run -itd \
  -e "AWS_ACCESS_KEY_ID=CHANGEME" \
  -e "AWS_SECRET_ACCESS_KEY=CHANGEME" \
  --name formio-seaweedfs \
  --restart unless-stopped \
  -p 8333:8333 \
  -p 23646:23646 \
  -v ~/seaweedfs/data:/data \
  chrislusf/seaweedfs server -s3
```

{% hint style="warning" %}
Note that the sample credentials "CHANGEME" should be updated to reflect the credentials intended for access to the file storage.
{% endhint %}

In this example, note that SeadweedFS is mounting the folder `~/seaweedfs`. This can be changed to any drive on the system machine where SeaweedFS should store files.

2. Verify the formio-seaweedfs container is running by executing the following command:

```
docker ps
```

The result should look similar to the following:

![](/files/6gWYhZJ8GjDOznLERrGQ)

3. Modify the `hosts` file to allow easy access to SeaweedFS:
   * **On MacOS/Linux:** From the terminal run the following command, logging in if prompted:

<pre><code><strong>sudo nano /etc/hosts
</strong></code></pre>

* **On Windows:** Use Notepad as an Administrator to open the file `C:\Windows\System32\Drivers\etc\hosts`\
  \
  Once the file is open, modify the appropriate line to read:

```
127.0.0.1       localhost seaweedfs Save the file and exit the text editor.
```

4. Start the admin portal with the command:

```
docker exec -it local-seaweedfs-1 /usr/bin/weed admin
```

5. In a browser, navigate to [http://seaweedfs:23646/](http://minio:9001/) ( or <http://localhost:23646>) to view the SeaweedFS interface.
6. After successfully loading the SeaweedFS dashboard, navigate to **Buckets** under the Object Store tools on the left-hand menu.

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

7. Create a new Bucket by clicking on the +**Create Bucket** button. Give the bucket a descriptive name and record the choice for future configurations.

The SeaweedFS Server should now be operational.

### Using NGROK for local testing (Optional)

To test this capability locally, the tool [**NGROK**](https://ngrok.com/) can be used to create a web accessible proxy to the local host. [Create an NGROK account](https://dashboard.ngrok.com/signup) and install the application, then run the following command to create a secure web tunnel to the localhost:

```
ngrok http 8333
```

### Form.io Configuration <a href="#formio-configuration" id="formio-configuration"></a>

Once SeaweedFS Server is running, configure the Form.io Platform settings to point to the running SeaweedFS endpoint in the Form.io Project settings. Complete the following steps:

1. Open the project in the Form.io platform.
2. Open the **Settings** menu from the left-hand pane.
3. From the **Settings** menu, navigate to **Integrations > File Storage**.
4. On the **Amazon S3** tab, check the **Use MinIO Server** box.
5. Configure the SeaweedFS settings as follows:
   * **SeaweedFS Server URL-** [*http://seaweedfs:8333*](http://minio:9000)\
     Form.io may display an error requesting a complete URL. It can be disregarded; the settings can be saved despite the warning.
   * **Access Key ID-** Enter the value specified for `AWS_ACCESS_KEY_ID`.
   * **Secret Access Key-** Enter the value specific for `AWS_SECRET_ACCESS_KEY`.
   * **Bucket Name-** Enter the name of the bucket created in the SeaweedFS dashboard.

![](/files/wpyIr96TJqOA1RVRXD4s)

6. Press **Save** to save your settings.

### Create a Form that uses SeaweedFS <a href="#create-a-form-that-uses-minio" id="create-a-form-that-uses-minio"></a>

To verify file storage has been correctly integrated, create a new API Web Form that has a **File** component.

After dropping the File component on the Form, open the configuration options. Open the **File** tab and verify that **Storage** is set to **S3**.

![](/files/l8Hd6uhtW76YbDkIwPIl)

Use the Form to upload a file. Verify that there are no errors on the Form, and that the file is placed in the SeaweedFS bucket as expected.

## Google Drive

Google Drive allows for external applications to create and update files within the Google platform. Before File Storage can be configured for Google Drive, you must first establish a connection between the Google Developer Cloud and Form.io. Follow the File Storage steps below once the Google Drive configuration is complete.

{% hint style="info" %}
[**Click Here**](/dev/integrations/google-developer-console) for documentation on how to integrate Google Developer Cloud with Form.io.
{% endhint %}

1. Within the Form.io Project, navigate to the Google Drive file storage settings\
   **Settings** > **Integrations** > **File Storage** > **Google Drive**
2. Click the **Enable Google Drive** button to configure the storage integration

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

3. Add a **File Component** to your form
   * Click the File tab
   * Select the **Google Drive** from the **Storage** dropdown

<figure><img src="/files/3p5PRJ0vZemPDzdUUXfk" alt=""><figcaption></figcaption></figure>

**File Folder**

If you want to route your file uploads to a specific folder in your Drive, simply add the Folder ID found within the URL to the Folder ID setting within the File component.

1. Navigate to your Google Drive folder
2. Copy the Folder ID within the URL

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

3. Add the ID to the Folder ID field within the File Component settings.

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


# Google Developer Console

[**Google Developer Console**](https://console.cloud.google.com/) allows you to build, deploy, and scale applications, websites, and services on the same infrastructure as Google. Form.io offers several direct integration options under the Google Developer Console umbrella such as:

* [**Google Drive Storage**](/dev/integrations/file-storage)
* [**Google Oauth**](https://developers.google.com/identity/protocols/oauth2)
* [**Google Sheets**](https://help.form.io/form-building/actions#webhook-action-1)

To leverage these features, a Google project must first be established and then integrated with a Form.io Project. The following documentation will guide you through creating a Google project, establishing the correct APIs, and connecting it to your Form.io project.

### Google Project

1. Login to your [**Google Developer Console**](https://console.cloud.google.com/)
2. Click the +Create Project button (or select an existing one)
3. Give the Project a name and click **Create**

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

### Configure Consent Screen

The **Google Developer Console Consent Screen** is part of the OAuth 2.0 authorization process used by applications requesting access to Google user data. When an application wants to access a user's data (e.g., their Google Drive files, calendar, or email), the consent screen is presented to the user. It allows them to review and grant permissions to the application before any data is accessed. Before the Google APIs can be integrated with Form.io, the consent screen must first be configured.

1. Within your Google project navigation bar, click the **APIs and Services** product and then **OAuth consent screen**
2. Select a Google [**User Type**](https://support.google.com/cloud/answer/10311615#user-type\&zippy=)

<figure><img src="/files/D3vPD3J57PETzAygSsTv" alt="" width="563"><figcaption></figcaption></figure>

3. Fill out the required **application fields**

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

3. Click **Save and Continue** through the application setup. Add any **Scopes** or **Test** **Users** if needed for your application.

{% hint style="info" %}
By default, the application status will be set to Testing[^1]. In this Status, the application [**Refresh Token** ](#google-refresh-token)will continually expire. A manual refresh of the token is required or a setting can be configured that will refresh the token automatically after the expiration window.

You can also Publish your application
{% endhint %}

3. By default, the application status will be set to Testing[^1]. In this Status, the application [**Refresh Token** ](#google-refresh-token)will continually expire.

### Enabling Google APIs

1. Within your Google project navigation bar, click the **APIs and Services** product and then **Library**

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

2. Select the **Google Drive API** and **Google Sheets API**

<figure><img src="/files/8d87ojFYPjlz6ZREoAYk" alt=""><figcaption></figcaption></figure>

3. Click **Enable** for both the Google Drive and Google Sheet APIs

<figure><img src="/files/VZK7IPhYaI1mRkbbhN4c" alt="" width="563"><figcaption></figcaption></figure>

### Application Credentials

1. Within your Google project navigation bar, click the **APIs and Services** product and then **Credentials**
2. Click the **+Create Credentials** button
3. Select **OAuth client ID**

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

4. Select the **Web Application** option
5. Within the **Authorized redirect URIs section**, click the **+ADD URI** button and add the following:\
   `https://developers.google.com/oauthplayground`
6. Click the **Create** button

<figure><img src="/files/xjocSutSp8BJrE4xJ5Mk" alt="" width="542"><figcaption></figcaption></figure>

7. Take note of the **Client ID** and **Client Secret**. This information will be used in the next section.

<figure><img src="/files/ImUC7vFLlQ08DR9N8yFQ" alt="" width="360"><figcaption></figcaption></figure>

### Google Refresh Token

Generates a token that allows users access to the Google APIs.

1. **Navigate** to the following URL:\
   [**https://developers.google.com/oauthplayground**](https://developers.google.com/oauthplayground/)
2. Click the **Gear** icon found in the top right corner of the page.
3. Ensure the following settings are configured
   * OAuth flow: **Server-side**
   * Access type: **Offline**
4. Check the **Use your own OAuth credentials**
   * Add the Google Project Client ID and Client Secret from the previous steps
   * Click the **Close** button

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

4. Within the API list, expand the **Google Sheets API v4**
   * Check the following API endpoints\
     <https://www.googleapis.com/auth/drive\\>
     <https://www.googleapis.com/auth/spreadsheetsXCCC>
5. Click the **Authorize APIs** button

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

6. Authenticate into the Google Drive platform
7. Click **Allow** to give the Google Project access to the Google Drive of the authenticated user
8. Click the **Exchange authorization code for tokens** button
9. Take note of the **Access Token** and the **Refresh Token**

{% hint style="info" %}
Enable the '**Auto-refresh token before expiration**' setting to automatically generate a new token when the current one expires. If this setting is not enabled, users will need to manually refresh the token or update the expiration time
{% endhint %}

<figure><img src="/files/8oPn10qo67YyVN6vVxdW" alt=""><figcaption></figcaption></figure>

### Form.io Integration

Integrate the Google Project into the Form.io Project.

1. Within the Form.io Project, navigate to the **Google Drive** configuration\
   **Settings** > **Integration** > **Data Connections** > **Google Drive**
2. Input the **Client ID** and **Client Secret** from the [**Application Credentials**](#application-credentials) section
3. Input the **Refresh Token** from the [**Google Refresh Token** ](#google-refresh-token)section

<figure><img src="/files/9RQul2BoXxkOTfhKU7ZI" alt=""><figcaption></figcaption></figure>

[^1]: If your app is still being tested and built, you can set your status to "testing". In this state, you can test your app with a limited number of users.


# Relational Databases

While Form.io [forms](/form.io-concepts#forms) and [resources](/form.io-concepts#resources) are one way an application may collect and store data, many customers use relational databases such as SQL to store data used within their application.

in many instances, customers want to synchronize data between a DB and Form.io. For example, they may want to pull information from a DB to populate choices in a select box. Alternatively, they may want to send submission data directly to their DB where it is consumed elsewhere in their application.

## Using Form.io with an external database

There are several methods of working with relational databases and Form.io depending on the specific requirements of the application.

### Webhooks

[Webhooks](/form-building/actions/webhook-actions) can be used to synchronize data from Form submissions to a SQL database.\
Webhooks are configurable [Form.io Actions](/form-building/actions) that are fired upon form submission and make a call to an external API endpoint. By configuring the payload to contain submission data, it can be shuttled into other applications or databases through the application or middleware behind that API endpoint.

This approach is useful for synchronizing data with an external database that serves as the source-of-truth for the application.

### Custom API Layer

Instead of connecting Form.io directly to a SQL database, a custom backend service (Node.js, Python, etc.) can be used to communicate between Form.io and the SQL DB. Such a service would generally:

1. Listen for Form submissions (via webhooks or API calls).
2. Transform the submission data as needed.
3. Store the data in the SQL database.
4. Fetch data from the SQL when needed and provide it to the Form.io front end.

This approach keeps the SQL database structure independent from the Form.io schema while also maintaining data synchronization.

### Use Form.io Data Sources

A Form.io [Resource ](/form.io-concepts#resources)can be used to pull data from an external SQL database if that DB is exposed via an API (Express.js, Django, etc.).

This allows a form to dynamically present or use existing external data from the DB.

For additional information on pulling external data into a Form.io resource, refer to the [Data Source Component](/form-building/data-components) documentation.

### The Form.io Server SDK

For greater control when running a deployed Form.io instance, the backend may be modified to support direct SQL database integration.

This may be appropriate when a high degree of customization is required, but involves a significant degree of novel development.


# Enterprise Form Builder Module

Integrating a robust form building and management tool in an application with the Enterprise Form Builder Module.

## Introduction

The Form.io **Enterprise Form Builder Module** is a form building and form management utility that is completely embeddable within an application. This decouples the form building and form management functions from application development.\
Enterprise Form Builder Module is analogous to the function of the Developer Portal, however the Enterprise Form Build Module functions entirely within the application environment.

When the form builder and manager is deployed within an application through the Enterprise Form Builder Module, the module implements custom routing to attach any created forms to a project. The forms can then be managed both through with the module's own form management tools as well as by accessing that project through the Form.io Developer Portal.

The embedded form builder and manager experience can be customized to the application context. The components and functionality can be configured to limit form builders within the application to certain components or to customize the behavior of components.

{% hint style="info" %}
The Enterprise Form Builder Module is a separately licensed module. It requires a unique [library license](/admin/licensing/library-licenses#using-a-library-license) separate from and in addition to the platform license. For information about purchasing a license, contact `sales@form.io`
{% endhint %}

## Overview of Features

The Enterprise Form Builder Module supports a wide range of embedded Form.io Enterprise features, such as:

* **Manage Forms:** Create, List, Edit, and Delete forms.
* **Form Edit conflict resolution:** Multiple builders can safely modify the same form at once.
* **Routing logic and guards:** Prompt a form user with unsaved changes before navigating away from a modified form.
* **Integrated Premium Components**
* **Custom Form Builder configurations**
* **Fully customizable components and route resolvers**

## Components and Modules

The Enterprise Form Builder provides pre-defined modules that serve as a scaffold for embedding form building and form management functions in an application. It accomplishes this by introducing the routing logic, resolvers, and components that are used for the common CRUD operations used when managing forms.

## Getting Started with Enterprise Form Builder Module

This guide covers two aspects of getting started with the Enterprise Form Builder Module:

1. [Application Integration](/dev/enterprise-form-builder-module/application-integration) - This describes the implementation of the Enterprise Form Builder Module within the host application.
2. [Using Enterprise Form Builder](/dev/enterprise-form-builder-module/using-enterprise-form-builder) - This describes using the Enterprise Form Builder to create and manage forms within the host application.


# Using Enterprise Form Builder

Once the Enterprise Form Builder module has been properly installed and integrated within your environment, the Module is ready to be used.

{% hint style="info" %}
If you do not see the Form Builder Pro within your project, ensure the module has been properly [**installed**](/dev/enterprise-form-builder-module/application-integration) and the correct [**library** **license** ](/admin/licensing/library-licenses)has been allocated to your environment.
{% endhint %}

This documentation mentions both, **Form Builder Pro** and **Enterprise Form Builder**. These are related, but distinct, parts of the platform:

* **Form Builder Pro:** UI within a Form.io project that developers utilize to manage and customize the Enterprise Form Builder.
* **Enterprise Form Builder:** The form builder embedded within your application controlled by Form Builder Pro.

## Accessing Form Builder Pro

Once enabled, the Form Builder Pro will be available in the UI of a project.

1. Navigate to any **project** within your deployed environment.
2. Click the **Builder Pro** tab from the left-hand navigation bar.

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

## Form Builder Pro UI

The Enterprise Form Builder Module provides a user-friendly interface called **Form Builder Pro** for creating a custom form builder that can be embedded directly into your application. Any changes made within Form Builder Pro will directly update the Enterprise Form Builder embedded within your app.

<figure><img src="/files/6vZCRD80coW6346X3Py6" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="253.63037109375">Setting</th><th>Description</th></tr></thead><tbody><tr><td><strong>Import Form Builder JSON</strong></td><td>Import a JSON file from another Project or Stage to include the configurations and settings of the exported Form Builder Pro.</td></tr><tr><td><strong>Remove Builder Configuration</strong></td><td>Removes <strong>all</strong> configurations and custom settings, returning the builder , including all custom groupings, settings, and fields to their default state.</td></tr><tr><td><strong>Default Groups</strong></td><td>The default components groupings that contain the Form Builder components.</td></tr><tr><td><strong>Custom Groups</strong></td><td>Create a new component grouping for the Form Builder containing standard or Pre-Defined fields.</td></tr><tr><td><strong>Edit Form Options</strong></td><td>Customize the general setting tabs for all components and settings specific to an individual component.</td></tr><tr><td><strong>Next</strong></td><td>Navigate through the Form Builder Pro tabs</td></tr><tr><td><strong>Save Builder Configurations</strong></td><td>Saves all configurations and settings. This will update the Enterprise Form Builder in real time embedded within your application.</td></tr></tbody></table>

## Default Groups

The default component groups available in the Enterprise Form Builder. These groups reflect the same Form.io groupings found within the standard builder included in the a Form.io Project.

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

#### **Removing Default Groups**

At times, entire component groupings might not be relevant for your Form Building requirements. Any default grouping can be toggled on or off as needed, removing the group and all components inside the group from the Enterprise Form Builder.

1. Within the Form Builder Pro UI, click the **Default Groups** tab
2. **Uncheck** a grouping to remove both the group and all component inside this group from the Enterprise Form Builder.

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

&#x33;**.** Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

<figure><img src="/files/4eeUyJLFgPJoem968wU8" alt=""><figcaption><p>Enterprise Form Builder with the Data and Premium groups removed</p></figcaption></figure>

#### **Removing Default Components**

To remove a component from a default group, start by expanding the group to view all included components. Simply uncheck the components that are not required for the Enterprise Form Builder to remove them from the Default Group.

1. Click the + **button** to expand the grouping, displaying available components within that grouping
2. **Uncheck** a Component to remove it from the grouping and builder

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

&#x33;**.** Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

<figure><img src="/files/DhxlDbAYdQLYBTxF7NqX" alt=""><figcaption><p>Enterprise Form Builder - Various components removed from Advanced group</p></figcaption></figure>

## Custom Groups

Custom groups are utilized to house default or pre-defined components within the Enterprise Form Builder.

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

#### Custom Group Settings

<table data-header-hidden><thead><tr><th width="182.2799072265625"></th><th></th></tr></thead><tbody><tr><td><strong>Title</strong></td><td>The name of the Custom Group that will display within the builder.</td></tr><tr><td><strong>Key</strong></td><td>The backend identifier for the custom group.</td></tr><tr><td><strong>Weight</strong></td><td>Numerical order of where the custom group will appear in the grouping list.</td></tr><tr><td><strong>Default</strong></td><td>Checking the Default checkbox will expand this group when a user initially opens the builder, revealing the available components within the group.</td></tr><tr><td><strong>Default Components</strong></td><td>Form.io default components that can be added to the custom group.</td></tr><tr><td><strong>+Add Another</strong></td><td>Add a new Custom Group</td></tr><tr><td><strong>Save/Cancel</strong></td><td>Save or Cancel the custom group.</td></tr></tbody></table>

#### Creating Custom Groups

1. Click the **Custom Groups** tab.
2. Click the **+Add Another** button.

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

3. Input a **Title** for the group. This title will be the group's name within the Enterprise Form Builder.
4. Set a **Key** for the group which will be used to reference the custom group programmatically.
5. Set a **Weight** to the group to determine its position relative to other groups within the Enterprise Form Builder.
6. Check the **Default** setting to have this Custom Group expanded by default when users initially open the Enterprise Form Builder
7. Add any standard Form.io **Default Components** that should be included within the Custom Group.

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

&#x38;**.** Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

<figure><img src="/files/8G2QdlxIFdED4fTCrjZt" alt=""><figcaption><p>Enterprise Form Builder - Custom Group with Default Components</p></figcaption></figure>

### **Pre-Defined Components**

Enhance custom group by adding predefined components, making them available for use within the Enterprise Form Builder. These components are built on standard Form.io components. Settings can be further tailored to fit the specific requirements of your application's form building needs.

#### Pre-Defined Component Settings

<table><thead><tr><th width="138.95465087890625">Setting</th><th>Description</th></tr></thead><tbody><tr><td><strong>Title</strong></td><td>The name of the Pre-Defined Component that will display within the custom group.</td></tr><tr><td><strong>Key</strong></td><td>The backend identifier of the component within the custom group.</td></tr><tr><td><strong>Icon</strong></td><td>Add icons based on the CSS framework being utilized within your application.</td></tr><tr><td><strong>Save/Cancel</strong></td><td>Save or Cancel the Custom Group settings. Users will still need to click the <strong>Save Builder Configurations</strong> in order to save the changes.</td></tr><tr><td><strong>+Add Another</strong></td><td>Add and define a new Component to the Custom Group.</td></tr></tbody></table>

#### Creating Pre-Defined Component

1. Within the Custom Group, click the **+Add Another** button. This will present a new set of fields to define the component.
2. Add a **Label** which will represent the default name of the component within the custom group.
3. The **Key** will auto-populate based on the Label input. This identifier will be used within the custom group to communicate with the backend APIs.
4. Add an **Icon** to the field based on the CSS framework type used within your application. The icon will display next to the field Title when viewing the component in the Enterprise Form Builder

{% hint style="info" %}
In this example, [**Bootstrap**](https://icons.getbootstrap.com/) is being utilized as the application's front-end framework, so the Icon name in this instance will look something like this\
`bi bi-info`

The icon will require a different naming convention depending on the type of front-end framework your application is utilizing.
{% endhint %}

<figure><img src="/files/9pkguzXPAWRcOIjcsq3G" alt=""><figcaption></figcaption></figure>

5. Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

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

{% tabs %}
{% tab title="Schema Fields" %}
The Schema Field settings define the name and type of the component that will appear when a form builder adds this pre-defined field to a form using the Enterprise Form Builder. Settings like the Label and Key will auto-populate based on the [**Title/Key**](#pre-defined-component-settings) settings set for the Pre-Defined Component but can be changed if needed.

These settings can differ from the Pre-Defined Component settings found above. A unique Label and Key can be given to the component which will represent the component name when a Form Builder adds the component to the Enterprise Form Builder vs the component name that appears inside the Custom Group.

#### Schema Field Settings

<table><thead><tr><th width="163.416748046875">Setting</th><th>Description</th></tr></thead><tbody><tr><td><strong>Label</strong></td><td>The default, front-end name of the component that will display for the end-user. The Label will auto-populate based on the Pre-Defined Component <a href="#pre-defined-component-settings"><strong>Title</strong></a>.</td></tr><tr><td><strong>Key</strong></td><td>The back-end identifier of the component that will communicate with the APIs. This field is auto-populated in camelCase based on the initial <a href="#pre-defined-component-settings"><strong>Key</strong></a> given in the Pre-Defined Component settings. Each field's Property Name must be unique on the form before the form can be saved.</td></tr><tr><td><strong>Type</strong></td><td>Select a default component the pre-defined component will be based on. All settings will carry over from the default component.</td></tr><tr><td><strong>Input</strong></td><td>Saves the input data to the submission object.</td></tr></tbody></table>

#### Add Schema Settings Component

1. Within the Custom Group, click the **+Add Another** button. This will present a new set of fields to define the component.
2. Add a **Label** which will represent the default name of the component when the component is added to the form using the Enterprise Form Builder.
3. The **Key** will auto-populate in camelcase based on the Label input. This identifier will be used in the context of the form to communicate with the backend APIs.
4. Select the Component **Type** from the list of Form.io fields the component will be based on. In this example, since this is a text input name field, the Text Field has been selected.

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

5. Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

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

Notice the Field Title within the group is called Applicant's Name, while the field Label is First Name when added to the builder.
{% endtab %}

{% tab title="JSON Schema" %}
Use the JSON Schema to configure settings that will be set by default when the component is added to the form. These settings should be based on the component Type found within the Schema Fields tab. Utilize the Edit JSON button for a component found within the Form.io builder to easily copy and paste the desired property settings needed into the JSON schema code block.

1. Within a Form.io Project, **add** the base component to the Form Builder. In this example, we are using a Text Field for the **Applicant's Name** field

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

2. **Configure** any **settings** that should be set for the Pre-Defined component. In this example, a Placeholder and Required validation has been added to the field.

<figure><img src="/files/4Ojts6Ms6hrLLh6v7OQj" alt=""><figcaption></figcaption></figure>

3. Click the **Edit** **JSON** button for the component found within the UI of the Form.io Form Builder and copy the JSON Schema.

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

4. **Copy** the **JSON** **Schema** containing the component setting properties.

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

5. Within **Form** **Builder** **Pro**, paste the setting properties copied from step 4 and paste them into the JSON Schema code block of the Pre-Defined Field

<figure><img src="/files/3AxLkTtswsNNqueTLMfT" alt=""><figcaption></figcaption></figure>

[**Click here for a full list of Component JSON Schema**](https://github.com/formio/formio.js/wiki/Components-JSON-Schema#common-parameters)<br>

6. Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

<figure><img src="/files/Sn2NzByohbaINyAJeBbH" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Edit Form Options

Customize standard components within the Enterprise Form Builder by adding or removing their default settings. Any Form Option changes made will effect available component settings when creating or updating [**Pre-Defined Fields**](#pre-defined-components).

### **Show Tabs**

A list of *general* setting tabs that are included for all components. Unchecking a tab will remove the setting tab for all components within the Enterprise Form Builder, including any Pre-Defined Components within your Custom Groups.

<figure><img src="/files/3Dg0X3osOWblhEFC8NVf" alt=""><figcaption></figcaption></figure>

**Toggling Setting Tabs**

1. Click the **Edit Form Options** tab
2. Navigate to the **Show Tabs** panel
3. **Toggle** the desired **Setting** group to remove the tab and all settings found within the tab from components within the Enterprise Form Builder

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

4. Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

<figure><img src="/files/11lNr3K6RC28XT6TwXQc" alt=""><figcaption><p>API and Layout setting tabs removed</p></figcaption></figure>

### **Show Fields**

A complete list of default components included in the Enterprise Form Builder. Opening the component panel will display all available settings specific to the component. Uncheck a setting to remove it from the Enterprise Form Builder. If a general setting tab has been disabled , a message will display saying this setting tab has been disabled.

{% hint style="info" %}
Any field settings you remove will also affect Pre-Defined fields that use this component as their Type
{% endhint %}

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

**Toggling Individual Settings**

1. Click the **Edit Form Options** tab
2. Navigate to the **Show Fields** panel
3. **Expand** the Component panel you wish to modify settings for.
4. **Toggle** the desired **Setting** to remove that setting from the component options.

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

5. Click '**Save Builder Configuration**' to apply your settings. Update your application to reflect the changes in the Enterprise Form Builder.

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


# Application Integration

## Getting Started

The Enterprise Form Builder Module exists entirely within an application external to the Form.io Platform. The following section describes the process of embedding the Enterprise Form Builder into an application.

### Prerequisites

Before proceeding, ensure the following have been completed:

1. The Form.io Platform has been deployed and is operational.
2. A Project has been created that will be used to store forms created within the Enterprise Form Builder Module.
3. A library license for the Enterprise Form Builder Module has been issued.
4. A suitable application is available.

## Integrating Enterprise Form Builder Module into an Application

There are two distinct paths depending on whether Enterprise Form Builder Module will be installed into an Angular or a React application. Choose the installation guide that matches the application:

<table data-card-size="large" data-view="cards"><thead><tr><th data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><a href="/pages/VhmLFoXs0apD1gpY3VZT">/pages/VhmLFoXs0apD1gpY3VZT</a></td><td data-object-fit="contain"><a href="/files/6zq2e45sPPN67iD5rrJR">/files/6zq2e45sPPN67iD5rrJR</a></td></tr><tr><td><a href="/pages/P6vCc9s9BFGefLkCO12O">/pages/P6vCc9s9BFGefLkCO12O</a></td><td data-object-fit="contain"><a href="/files/cG26PJqVhC0RvIodbKA0">/files/cG26PJqVhC0RvIodbKA0</a></td></tr></tbody></table>


# Angular Applications

Installing the Enterprise Form Builder Module in an Angular application.

This walkthrough uses the sample Angular application created in the [Application Development](/dev/application-development#create-an-application) procedure in the Developer Guide.

{% hint style="warning" %}
The Enterprise Form Builder Module **requires** the NgModule method of Angular application structure.

When creating a new Angular application, provide the following configuration to ensure it uses the NgModule method:

```
ng new [appname] --standalone false --routing true
```

{% endhint %}

## Install the Enterprise Form Builder Module into the App

1. Use one of the following terminal commands to install the @formio/enterprise-builder module into the application:

```bash
npm i --save @formio/js @formio/premium @formio/enterprise-builder
```

or

```bash
yarn add @formio/js @formio/premium @formio/enterprise-builder
```

2. Install the framework-specific libraries as follows:

```bash
npm i --save @formio/angular
```

or

```bash
yarn add @formio/angular
```

3. Set the license key with the following code snippet:

```javascript
import { Formio } from '@formio/angular';

Formio.license = 'yourLibraryLicenseKey';
```

making sure to replace *yourLibraryLicenseKey* with the appropriate [Library License](/admin/licensing/library-licenses).

## Configure the Application

To configure the sample Angular application to use the Enterprise Builder Module, complete the following steps:

1. Create a configuration file in the format of **EnterpriseBuilderConfig** as shown below:

{% code title="app.config.ts" %}

```javascript
import { EnterpriseBuilderConfig } from '@formio/enterprise-builder/angular';
export const AppConfig: EnterpriseBuilderConfig = {
  license: '-- ENTER YOUR LICENSE HERE --',
  baseUrl: 'https://forms.example.com',
  projectUrl: 'https://forms.example.com/myproject',
  tag: 'common'
};
```

{% endcode %}

The following configurations can be provided to the Enterprise Builder Module:

| Property   | Description                                                                                          | Example                                  |
| ---------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| license    | The license for the Enterprise Form Builder module.                                                  |                                          |
| baseUrl    | The URL for the Form.io Enterprise deployment.                                                       | <https://forms.example.com>              |
| projectUrl | The Project URL to "mount" for form management within this application.                              | <https://forms.example.com/myproject>    |
| tag        | The tag to use when searching the forms in the Forms index.                                          | common                                   |
| icons      | The icon class to use in the renderer.                                                               | bi - (for Bootstrap Icons)               |
| config     | An object of configurations to pass to the Formio.config SDK used to configure how the SDK operates. |                                          |
| showData   | A boolean to enable the Submission management as part of the mounted form mangement routes and UI.   | true - To show the submission management |

2. Tell the application to use this configuration when mounting the module.\
   Set the FormioAppConfig service to use the extended EnterpriseBuilderAppConfig service, and then provide the ENTERPRISE\_BUILDER\_CONFIG token as follows:

{% code title="app.module.ts" %}

```javascript
import { FormioAppConfig } from '@formio/angular';
import {
    EnterpriseBuilderAppConfig,
    ENTERPRISE_BUILDER_CONFIG
} from '@formio/enterprise-builder/angular';
import { AppConfig } from './app.config';

@NgModule({
    declarations: [...],
    imports: [...],
    providers: [
        ...,
        {provide: ENTERPRISE_BUILDER_CONFIG, useValue: AppConfig},
        {provide: FormioAppConfig, useClass: EnterpriseBuilderAppConfig},
        ...
    ]
})
export class AppModule {}
```

{% endcode %}

3. Ensure that all styles added to the application are supported by the Enterprise Form Builder Module.\
   By default, the Enterprise Form Builder Module supports[ Bootstrap 5](https://getbootstrap.com/).

{% hint style="info" %}
To change the CSS template, extend the components as documented later in this guide.
{% endhint %}

To enable Bootstrap, install it within the application as follows:

```bash
npm i --save bootstrap bootstrap-icons bootswatch
```

or

```bash
yarn add bootstrap bootstrap-icons bootswatch
```

4. Configure the application to use this theme with the following code:

{% code title="src/styles.scss" %}

```scss
@import "bootstrap/scss/bootstrap.scss";
@import "bootswatch/dist/cosmo/variables";
@import "bootswatch/dist/cosmo/bootstrap";
@import "@formio/js/dist/formio.full.css";
@import "bootstrap-icons/font/bootstrap-icons.scss";
```

{% endcode %}

This uses [Bootswatch](https://bootswatch.com/) to offer multiple themes. Alter the theme by changing the word *cosmo* to the preferred theme.

Once the configurations and styles in place, the next objective is to set up User Authentication within the application.

## User Authentication

User authentication is required to support form management within a project.

These steps will configure the project to have a User role that will manage the forms:

1. From the Developer Portal, open the associated project.
2. Navigate to **Access**, then click **New Role** under the list of existing Project Roles.
3. Enter the title *Form Builder* and click **Create Role**.\
   The screen should return to the Access page.

{% hint style="info" %}
Refer to [Roles documentation](/how/role-based-conditions#create-roles) for additional information.
{% endhint %}

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

4. On the **Access** page, add the Form Builder role to the following Permission groups:
   1. Create All
   2. Read All
   3. Update All
   4. Delete All

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

5. Configure the Project to add these roles to the authenticated users group. Do this using the [SSO configurations](/dev/authentication-and-authorization/saml#introduction), or using [Form.io Authentication](/dev/authentication-and-authorization#user-authentication).\
   Either option requires modifying the User Login form to enable this authentication.

Once the Form.io project is appropriately configured, configure authentication within the host application. The documentation for setting up Authentication within an Angular application can be found at the [Angular Authentication Documentation](https://help.form.io/dev/application-development#user-authentication).

With this route in place, application users can authenticate into the app and subsequently be authenticated into the Form.io Project with the appropriate privileges.

## Application Alerts

Once Authentication is in place, the next objective is to bind the Enterprise Form Builder Module alert system with the host application.

By default, the Enterprise Form Builder Module uses a base service for when certain alerts are triggered within the **EnterpriseBuilderAlerts** service.

Typically, each application will have its own "alert" notification systems. For example, an application may chose to use [Toastr notifications](https://www.npmjs.com/package/ngx-toastr) with their applications when a notification is made. The Enterprise Form Builder Module provides a way to inject alerts generated by the Enterprise Form Builder Module into the host application's notification system.

The following example steps use the `ngx-toastr` module to add Toastr notifications to the application.

1. Install the module with the following commands:

```bash
npm i --save ngx-toastr
```

or

<pre class="language-bash"><code class="lang-bash"><strong>yarn add ngx-toastr
</strong></code></pre>

2. Add the service to the module as follows:

{% code title="app.module.ts" %}

```javascript
import { ToastrModule, provideToastr } from 'ngx-toastr';
...
...
@NgModule({
   ...
   imports: [
      ...
      BrowserAnimationsModule,
      ToastrModule.forRoot(),
      ...
   ],
   providers: [
      ...
      provideToastr(),
      ...
   ],
   ...
})
export class AppModule {}
```

{% endcode %}

3. Import the SCSS:

{% code title="styles.scss" %}

```scss
...
@import 'ngx-toastr/toastr';
```

{% endcode %}

4. Create a new wrapper Service for the EnterpriseBuilderAlerts service, like so:

```bash
ng g service app.alerts
```

5. Extend this service from the EnterpriseBuilderAlerts, and hook it into the **ToastrService** as follows:

{% code title="app.alerts.service.ts" %}

```javascript
import { Injectable } from "@angular/core";
import { ToastrService } from "ngx-toastr";
import { EnterpriseBuilderAlerts, Alert } from '@formio/enterprise-builder/angular';

@Injectable({
    providedIn: 'root'
})
export class AppAlertsService extends EnterpriseBuilderAlerts {
    constructor(public toastr: ToastrService) {
        super();
    }

    override add(alert: Alert) {
        this.toastr[alert.level](alert.message, alert.title);
        super.add(alert);
    }
}
```

{% endcode %}

6. Provide this in the application as follows:

{% code title="app.module.ts" %}

```javascript
import { EnterpriseBuilderAlerts, ... } from '@formio/enterprise-builder/angular';
import { AppAlertsService } from './app.alerts.service';
...
@NgModule({
    ...
    providers: [
        ...
        {provide: EnterpriseBuilderAlerts, useClass: AppAlertsService},
        ...
    ],
    ...
})
export class AppModule {}
```

{% endcode %}

Now, any alerts triggered by the Enterprise Form Builder Module will show within the host application alert system using the Toastr module.

## Mounting the Form Management UI

Next , "mount" the Form Management UI within the host application's routing system. This allows application users to navigate to a specific route within the application to see the Form Building UI provided by the Enterprise Form Builder Module. To do so, complete the following steps:

In Angular, use the *@angular/router* module for all routing for the Enterprise Form Builder Module. To accomplish this, complete the following steps:

1. Create a new Angular module that will encapsulate the forms module within the Enterprise Form Builder Module, using the following CLI command:

```bash
ng g module forms
```

2. Mount the FormRoutes in the RouterModule within the FormsModule using the following code:

{% code title="forms/forms.module.ts" %}

```javascript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { 
  FormsModule as EnterpriseBuilderFormsModule,
  FormRoutes
} from '@formio/enterprise-builder/angular';

@NgModule({
  imports: [
    CommonModule,
    EnterpriseBuilderFormsModule,
    RouterModule.forChild(FormRoutes())
  ]
})
export class FormsModule {}
```

{% endcode %}

{% hint style="info" %}
A later section will cover how all of the components at each route can be overridden and modified. For now, leave the defaults.
{% endhint %}

3. Mount this module within the routes using the *app-routing.module.ts*.

{% code title="app-routing.module.ts" %}

```javascript
...
const routes: Routes = [
  {
    path: 'auth',
    loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
  },
  {
    path: 'forms',
    loadChildren: () => import('./forms/forms.module').then(m => m.FormsModule)
  }
];
...
```

{% endcode %}

With the Enterprise Form Builder Module in place, navigate to the "forms" path within the host application (after authenticating) to see the full Form Building and Management UI as follows:

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

## Submission Management

By default, only the Form Management UI components are enabled. To enable the Submission management UI inside of this module, provide the following within the configurations:

{% code title="app.config.ts" %}

```javascript
import { EnterpriseBuilderConfig } from '@formio/enterprise-builder/angular';
export const AppConfig: EnterpriseBuilderConfig = {
  license: '-- ENTER YOUR LICENSE HERE --',
  baseUrl: 'https://forms.example.com',
  projectUrl: 'https://forms.example.com/myproject',
  tag: 'common',
  showData: true
};
```

{% endcode %}

Once enabled, the following UI is now available within each Form context:

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

{% hint style="info" %}
If not data is visible, or the table is stuck loading, make sure that the appropriate [submission read permissions](/admin/roles-and-permissions#submission-data-permissions) are set within the form.
{% endhint %}

## Components

The Enterprise Form Builder Module includes many different Components, mounted at different routes, that can be configured and overridden by the application embedding the module. The following components are included at the following routes:

{% hint style="info" %}
The path of the route is determined by the host application; ":host" is used to indicate the path at which the module is mounted.

For example, if FormsModule is mounted at the "forms" path within the application, then the placeholder ":host" would be replaced with ":forms".
{% endhint %}

### Component Overview

The following components are available.

For detailed information on each component, refer to the [Angular Component Reference](/dev/enterprise-form-builder-module/application-integration/angular-applications/angular-component-reference).

| Component                     | Description                                                                                                                                                                                                    | Route                                         |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| FormsComponent                | Provides the index of forms.                                                                                                                                                                                   | :host                                         |
| FormBuildComponent            | The component used to create a new form, that shows the form builder.                                                                                                                                          | :host/build                                   |
| FormComponent                 | The wrapper component for all child route components within the Form context. This provides the navigation UI for the "view", "edit" "delete", "settings" tabs for a specific form.                            | :host/:formId                                 |
| FormViewComponent             | The component used to view (or use) a form.                                                                                                                                                                    | :host/:formId/view                            |
| FormEditComponent             | Used to edit a form, allowing the builder to edit the current Form JSON.                                                                                                                                       | :host/:formId/edit                            |
| FormDeleteComponent           | Confirms and processes Form deletion.                                                                                                                                                                          | :host/:formId/delete                          |
| FormChangesComponent          | Notifies a form user that a form has been changed when they attempt to navigate away from the form context. It allows them to go back to the form context, or discard the form changes.                        | :host/:formId/changes                         |
| FormConflictComponent         | Shown to the user when a form conflict is identified between the form being saved to the server, and the form that already exists on the server, indicating that someone has already made changes to the form. | :host/:formId/conflict                        |
| FormSettingsComponent         | Provides an interface to allow a user to modify the metadata for the current form such as the title, name, path, tags, etc.                                                                                    | :host/:formId/settings                        |
| FormSubmissionsComponent      | Provides a view of the submissions for a form.                                                                                                                                                                 | :host/:formId/submission                      |
| FormSubmissionComponent       | The wrapper component for a Form Submission. Provides the navigation UI for the other child components such as view, edit, and delete. It also provides a button for downloading the submission as a pdf       | :host/:formId/submission/:submissionId        |
| FormSubmissionViewComponent   | The component used to view an existing submission within a form.                                                                                                                                               | :host/:formId/submission/:submissionId        |
| FormSubmissionEditComponent   | Used to allow the user to edit an existing submission.                                                                                                                                                         | :host/:formId/submission/:submissionId/edit   |
| FormSubmissionDeleteComponent | The component that provides an interface to the user to delete a submission.                                                                                                                                   | :host/:formId/submission/:submissionId/delete |

### Overriding Components

Each component can be overridden when the Enterprise Form Builder Module is embedded within the application. The following process is an example of how to override one of the components for the framework:

To override the UI when a Form is being viewed, alter the FormViewComponent by extending it.

1. Create a new component within the form module using the CLI tool as follows:

```bash
ng g component forms/view
```

2. This component can now extend the Enterprise Form Builder FormsViewComponent as follows:

{% code title="forms/view/view\.component.ts" %}

```javascript
import { Component } from '@angular/core';
import { FormViewComponent } from '@formio/enterprise-builder/angular';

@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrl: './view.component.scss'
})
export class ViewComponent extends FormViewComponent {}
```

{% endcode %}

3. Open a new browser tab and copy the existing HTML template found in the FormViewComponent by starting with the code available on the Form.io GitHub: <https://github.com/formio/enterprise-builder/blob/main/projects/enterprise-builder/src/form/view/view.component.html>
4. Paste the code in the overridden `view.component.html` like so:

<pre class="language-html" data-title="forms/view/view.component.html" data-overflow="wrap"><code class="lang-html"><strong>&#x3C;div class="bg-body rounded shadow-sm p-2">
</strong>    &#x3C;formio [src]="service.formUrl()" [form]="service.form"
            (submit)="onSubmit($event)" (error)="onFormError($event)">&#x3C;/formio>
&#x3C;/div>
</code></pre>

5. Modify the component as needed, for example:

<pre class="language-html" data-title="forms/view/view.component.html" data-overflow="wrap"><code class="lang-html">&#x3C;h3>{{ service.form.title }}&#x3C;/h3>
&#x3C;div class="bg-body rounded shadow-sm p-2">
<strong>    &#x3C;formio [src]="service.formUrl()" [form]="service.form"
</strong><strong>            (submit)="onSubmit($event)" (error)="onFormError($event)">&#x3C;/formio>
</strong>&#x3C;/div>
</code></pre>

6. Tell the Enterprise Form Builder Module to use the modified component instead of the default FormViewComponent. Do this in the Forms module, where FormRoutes is mounted. This function takes a configuration; provide the form view component as follows:

{% code title="form/form.module.ts" %}

```javascript
...
import { FormioEmbedModule } from '@formio/angular/embed';
import { FormsModule as EnterpriseBuilderFormsModule, FormRoutes } from '@formio/enterprise-builder/angular';
import { ViewComponent } from './view/view.component';

@NgModule({
  imports: [
    CommonModule,
    FormioEmbedModule,
    EnterpriseBuilderFormsModule,
    RouterModule.forChild(FormRoutes({
      view: ViewComponent
    }))
  ],
  declarations: [
    ViewComponent
  ]
})
export class FormsModule {}
```

{% endcode %}

Following a similar process, the following configurations can override any component within the Enterprise Form Builder Module:

```javascript
FormRoutes({
    index: MyFormsComponent,                // extend FormsComponent
    build: MyFormBuildComponent,            // extend FormBuildComponent
    form: MyFormComponent,                  // extend FormComponent
    view: MyFormViewComponent,              // extend FormViewComponent
    edit: MyFormEditComponent,              // extend FormEditComponent
    delete: MyFormDeleteComponent,          // extend FormDeleteComponent
    changes: MyFormChangesComponent,        // extend FormChangesComponent
    conflict: MyFormConflictComponent,      // extend FormConflictComponent
    settings: MyFormSettingsComponent,      // extend FormSettingsComponent
    submission: {
        index: MySubmissionsComponent,      // extend FormSubmissionsComponent
        submission: MySubmissionComponent,  // extend FormSubmissionComponent
        view: MySubmissionViewComponent,    // extend FormSubmissionViewComponent
        edit: MySubmissionEditComponent,    // extend FormSubmissionEditComponent
        delete: MySubmissionDeleteComponent // extend FormSubmissionDeleteComponent
    }
})
```


# Angular Component Reference

The following components are available:

* [FormsComponent](#formscomponent)
* [FormBuild](#formbuildcomponent)[Component](#formbuildcomponent)
* [FormComponent](#formcomponent)
* [FormViewComponent](#formviewcomponent)
* [FormEditComponent](#formeditcomponent)
* [FormSettingsComponent](#formsettingscomponent)
* [FormChangesComponent](#formchangescomponent)
* [FormConflictComponent](#formconflictcomponent)
* [FormDeleteComponent](#formdeletecomponent)
* [FormSubmissionsComponent](#formsubmissionscomponent)
* [FormSubmissionComponent](#formsubmissioncomponent)
* [FormSubmissionViewComponent](#formsubmissionviewcomponent)
* [FormSubmissionEditComponent](#formsubmissioneditcomponent)
* [FormSubmissionDeleteComponent](#formsubmissiondeletecomponent)

## FormsComponent

This component provides the index for the forms.

<figure><img src="/files/3tqPUOwLomQ5k7cReAJJ" alt=""><figcaption><p>The FormsComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="131.50390625"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/forms.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/forms.component.ts</a></td></tr><tr><td>Template</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/forms.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/forms.component.html</a></td></tr></tbody></table>

## FormBuildComponent

This component is used to create new forms in your application.

<figure><img src="/files/GLFMmcPNMftBtib5Ayuf" alt=""><figcaption><p>The FormBuildComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="151.078125"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/build</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/build/build.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/build/build.component.ts</a></td></tr><tr><td>Template</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/build/build.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/build/build.component.html</a></td></tr></tbody></table>

## FormComponent

The wrapper component for all child route components within the Form context. This provides the UI for the navigation to the "edit", "settings", etc for a specific form.

<figure><img src="/files/gymWNyc1xOGtHdUWotCW" alt=""><figcaption><p>FormComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="160.765625"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/form/form.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/form/form.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/form/form.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/form/form.component.html</a></td></tr></tbody></table>

## **FormViewComponent**

The component used to view (or use) a form.

<figure><img src="/files/t9gdPI0H0kL6wBfLd60f" alt=""><figcaption><p>FormViewComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="194.4140625"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/view</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/view/view.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/view/view.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/view/view.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/view/view.component.html</a></td></tr></tbody></table>

## FormEditComponent

The component used to edit a form providing the builder to edit the current Form JSON.

<figure><img src="/files/nev9j9JBAYYco2kXKj0i" alt=""><figcaption><p>FormEditComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="181.20703125"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/edit</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/edit/edit.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/edit/edit.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/edit/edit.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/edit/edit.component.html</a></td></tr></tbody></table>

## FormSettingsComponent

Provides an interface to allow a user to modify the metadata for the current form in context such as the title, name, path, tags, etc.

<figure><img src="/files/0vpYm5u6rxaICDTPuyFz" alt=""><figcaption><p>FormSettingsComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="174.375"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/settings</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/settings/settings.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/settings/settings.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/settings/settings.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/settings/settings.component.html</a></td></tr></tbody></table>

## FormChangesComponent

The component shown to a user when a form has been changed and the user attempts to navigate away from the form context. It allows them to either cancel the navigation away, or cancel their form changes.

<figure><img src="/files/PNZx9syIhfR8YQUzo4jk" alt=""><figcaption><p>FormChangesComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="183.171875"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/changes</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/changes/changes.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/changes/changes.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/changes/changes.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/changes/changes.component.html</a></td></tr></tbody></table>

## FormConflictComponent

This component is shown to the user when a form conflict has been identified between the form being saved to the server and the form that already exists on the server (meaning that someone has saved the form before the user saved their version).

<figure><img src="/files/ctteAASOzoTdMFA8F1nl" alt=""><figcaption><p>FormConflictComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="192.64453125"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/conflict</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/conflict/conflict.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/conflict/conflict.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/conflict/conflict.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/conflict/conflict.component.html</a></td></tr></tbody></table>

## FormDeleteComponent

The component used to ask the user if they wish to Delete the form, and if they confirm, performs the deletion of the form.

<figure><img src="/files/PUPVokbuCBYgjWQmp5Qp" alt=""><figcaption><p>FormDeleteComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="175.33203125"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/delete</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/delete/delete.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/delete/delete.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/delete/delete.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/delete/delete.component.html</a></td></tr></tbody></table>

## FormSubmissionsComponent

Provides an index of the submissions for a provided form context

<figure><img src="/files/279RMz3a31DFzEtTGkHD" alt=""><figcaption><p>FormSubmissionsComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="164.05078125"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/:formId/submission</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submissions/submissions.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submissions/submissions.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submissions/submissions.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submissions/submissions.component.html</a></td></tr></tbody></table>

## FormSubmissionComponent

The wrapper component for a Form Submission in context. Provides the navigation UI for the other child components such as view, edit, and delete.

<figure><img src="/files/xznNFvgmpy16bMr79UNq" alt=""><figcaption><p>FormSubmissionComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="170.8828125"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/form/:formId/submission/:submissionId</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submission/submission.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submission/submission.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submission/submission.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/submission/submission.component.html</a></td></tr></tbody></table>

## FormSubmissionViewComponent

The view component to view an existing submissions within a form.

<figure><img src="/files/xznNFvgmpy16bMr79UNq" alt=""><figcaption><p>FormSubmissionViewComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="169.4609375"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/form/:formId/submission/:submissionId</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/view/view.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/view/view.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/view/view.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/view/view.component.html</a></td></tr></tbody></table>

## FormSubmissionEditComponent

The component used to allow the user to edit an existing submission.

<figure><img src="/files/ygfrzmGSw2L5T3TsZspg" alt=""><figcaption><p>FormSubmissionEditComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="165.171875"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/form/:formId/submission/:submissionId/edit</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/edit/edit.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/edit/edit.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/edit/edit.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/edit/edit.component.html</a></td></tr></tbody></table>

## FormSubmissionDeleteComponent

The component that provides an interface to the user to ask them if they wish to delete a submission or not.

<figure><img src="/files/WFCfDDgXJaiaCgTvXaGO" alt=""><figcaption><p>FormSubmissionDeleteComponent UI</p></figcaption></figure>

<table data-header-hidden><thead><tr><th width="163.359375"></th><th></th></tr></thead><tbody><tr><td>Route</td><td>:host/form/:formId/submission/:submission/delete</td></tr><tr><td>Code</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/delete/delete.component.ts">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/delete/delete.component.ts</a></td></tr><tr><td>Template HTML</td><td><a href="https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/delete/delete.component.html">https://github.com/formio/enterprise-builder/blob/main/angular/src/projects/enterprise-builder/src/form/submissions/delete/delete.component.html</a></td></tr></tbody></table>


# React Applications

Integrating the Enterprise Form Builder Module in a React application.

Within a React application, the Enterprise Form Builder Moduler provides a suite of components and hooks that enable form building within an application while using the enterprise features available in Form.io.

In keeping with React application building conventions, it is a collection of components and does not utilize any third party routing or state management. Those capabililites remain in the domain of the application using the components.

All of the core interaction with the Form.io server is separated into hooks, so they can be used independent of the the UI components provided.

To begin using the Enterprise Form Builder Module within a React application, complete the following steps:

## Installation

To install the React Enterprise Form Builder package, use the following command:

```bash
npm install @formio/enterprise-form-builder-react
```

### **Required Peer Dependencies**

This package relies on both `@formio/react` and `@formio/js` as peer dependencies. They must be installed in the project if they are not already present:

```bash
npm install @formio/react @formio/js
```

Make sure the versions of `@formio/react` and `@formio/js` meet the minimum requirements specified in the package's `peerDependencies`.

## Setup <a href="#setup" id="setup"></a>

To use the Enterprise Form Builder in a React app, configure the required context providers at the top level of the application, just as in the `react-efb-demo` app.

The `EnterpriseFormBuilderProvider` must be a child of the `FormioProvider` in the application's component tree. Configure the `Formio` library with the license key and any additional client libraries.

Here is a minimal example of how to wrap an application:

```jsx
import React from 'react';
import { EnterpriseFormBuilderProvider } from '@formio/enterprise-form-builder-react';
import { FormioProvider } from '@formio/react';

const licenseKey = 'YOUR_ENTERPRISE_LICENSE_KEY'; // Replace with your license key

function App() {
  return (
    <FormioProvider
      projectUrl="https://your-project.form.io"   // <-- Change to your Form.io project URL
      baseUrl="https://your-domain.form.io"        // <-- Change to your Form.io base URL
    >
      <EnterpriseFormBuilderProvider licenseKey={licenseKey} tag="common">
        {/* Your app content and routing here */}
      </EnterpriseFormBuilderProvider>
    </FormioProvider>
  );
}

export default App;
```

**Notes:**

* The `FormioProvider` sets up Form.io project context for all children.
* The `EnterpriseFormBuilderProvider` enables the enterprise builder features and requires a valid license key.
* The `tag` prop is used to group forms that are available to the Enterprise Form Builder. New forms will be added with this tag and only Forms with the tag will be displayed.
* Wrap your app's router or main content with these providers.

## User Authentication

User authentication is required to support form management within a project.

These steps will configure the project to have a User role that will manage the forms:

1. From the Developer Portal, open the associated project.
2. Navigate to **Access**, then click **New Role** under the list of existing Project Roles.
3. Enter the title *Form Builder* and click **Create Role**.\
   The screen should return to the Access page.

{% hint style="info" %}
Refer to [Roles documentation](/how/role-based-conditions#create-roles) for additional information.
{% endhint %}

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

4. On the **Access** page, add the Form Builder role to the following Permission groups:
   1. Create All
   2. Read All
   3. Update All
   4. Delete All

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

5. Configure the Project to add these roles to the authenticated users group. Do this using the [SSO configurations](/dev/authentication-and-authorization/saml#introduction), or using [Form.io Authentication](/dev/authentication-and-authorization#user-authentication).\
   Either option requires modifying the User Login form to enable this authentication.

Once the Form.io project is appropriately configured, configure authentication within the host application. The documentation for setting up Authentication within an Angular application can be found at the [Angular Authentication Documentation](https://help.form.io/dev/application-development#user-authentication).

With this route in place, application users can authenticate into the app and subsequently be authenticated into the Form.io Project with the appropriate privileges.

## Error Handling <a href="#error-handling" id="error-handling"></a>

There are two ways to handle errors that come from the Enterprise Form Builder components:

* Each component has an `onError` callback function to allow you to handle the error as needed.
* If the `onError` callback is not provided, the error will be thrown. This allows you to use a global error handler such as a [React Error Boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) to catch and handle errors in your application.

## Providers <a href="#providers" id="providers"></a>

The [EnterpriseFormBuilderProvider](/dev/enterprise-form-builder-module/application-integration/react-applications/react-context-provider) is the context provider for enterprise form builder functionality. Refer to the [React Context Provider](/dev/enterprise-form-builder-module/application-integration/react-applications/react-context-provider)reference for more information.

## Components <a href="#components" id="components"></a>

The following components are available within React apps. Refer to the [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference) for more detailed information.

* CreateForms - Visual form builder interface for creating and editing forms
* FormList - Display and manage a list of forms with filtering
* FormViewer - Display a form for users to fill out and submit
* UseForm - Display a form with an existing submission for viewing or editing
* SubmissionList - Display a table of submissions for a form
* SubmissionViewer - View, edit, or delete a submission
* FormDelete - Confirmation dialog for deleting a form
* DeleteSubmission - Confirmation dialog for deleting a submission
* FormSettings - Edit form metadata (title, name, path, tags)

## Hooks <a href="#hooks" id="hooks"></a>

All hooks provided by the Enterprise Form Builder follow a consistent pattern: each hook returns an action function (such as `loadForm`, `saveForm`, `deleteForm`, etc.) that performs the associated operation, along with state properties that allow you to track the progress and result of the operation. These state properties typically include:

* `loading`: `boolean` — Indicates if the operation is currently in progress.
* `error`: `string | null` — Holds any error message if the operation fails, otherwise `null`.
* `success`: `boolean` — (For actions such as save or delete) Indicates if the operation was successful.
* Data property: The returned data from the operation, if applicable (such as `form`, `forms`, `submission`, etc.).

This pattern allows you to call the action function as needed (for example, in response to a button click or effect), and use the returned state properties in your component’s UI to provide feedback, handle errors, or display loading indicators.

The list of available hooks are listed below. Refer to the [React Hooks Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference) for more information:

* useEnterpriseFormBuilder - Access the enterprise form builder context
* useLoadForm - Load a single form by ID
* useLoadForms - Load multiple forms with optional query parameters
* useSaveForm - Save forms with optional conflict resolution
* useDeleteForm - Delete a form by ID
* useLoadSubmission - Load a single submission by form ID and submission ID
* useSaveSubmission - Save a submission
* useDeleteSubmission - Delete a submission
* useLoadProject - Load Form.io project information


# React Component Reference

The following React components are available:

* [#createforms](#createforms "mention")- Visual form builder interface for creating and editing forms
* [#formlist](#formlist "mention") - Display and manage a list of forms with filtering
* [#formviewer](#formviewer "mention") - Display a form for users to fill out and submit
* [#formviewer](#formviewer "mention") - Display a form with an existing submission for viewing or editing
* [#submissionlist](#submissionlist "mention") - Display a table of submissions for a form
* [#submissionviewer](#submissionviewer "mention") - View, edit, or delete a submission
* [#formdelete](#formdelete "mention")- Confirmation dialog for deleting a form
* [#deletesubmission](#deletesubmission "mention") - Confirmation dialog for deleting a submission
* [#formsettings](#formsettings "mention")- Edit form metadata (title, name, path, tags)

## CreateForms

A comprehensive form builder component that provides a visual interface for creating and editing forms using the Form.io builder.

### Summary <a href="#summary" id="summary"></a>

The `CreateForms` component renders a full-featured form builder with a toolbar for managing form metadata (title, path, display type) and a visual drag-and-drop interface for building forms. It handles form loading, saving, and change tracking automatically.

### Props <a href="#props" id="props"></a>

| Prop                | Type                       | Required | Description                                                 |
| ------------------- | -------------------------- | -------- | ----------------------------------------------------------- |
| `formId`            | `string`                   | No       | ID of the form to edit. If not provided, creates a new form |
| `onChange`          | `(form: FormType) => void` | No       | Callback fired when form structure changes                  |
| `onEditComponent`   | `(component: any) => void` | No       | Callback fired when a component is edited                   |
| `onDeleteComponent` | `(component: any) => void` | No       | Callback fired when a component is deleted                  |
| `onSaveComponent`   | `(component: any) => void` | No       | Callback fired when a component is saved                    |
| `onSaveForm`        | `(form: FormType) => void` | No       | Callback fired when the form is successfully saved          |
| `onUpdateComponent` | `(component: any) => void` | No       | Callback fired when a component is updated                  |
| `onError`           | `(error: Error) => void`   | No       | Callback fired when an error occurs                         |
| `onAddComponent`    | `(component: any) => void` | No       | Callback fired when a component is added                    |
| `Loading`           | `ReactNode`                | No       | Custom loading component to display while loading           |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { CreateForms } from '@formio/enterprise-form-builder-react';

function FormBuilderPage({ formId }: { formId?: string }) {
  const handleSave = (form) => {
    console.log('Form saved:', form);
    // Navigate to form list or show success message
  };

  const handleError = (error) => {
    console.error('Error:', error);
    // Show error notification
  };

  return (
    <CreateForms
      formId={formId}
      onSaveForm={handleSave}
      onError={handleError}
      Loading={<div>Loading form builder...</div>}
    />
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadforms) - Load form data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usesaveform) - Save form data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usesaveform)- Load project configuration

## FormList

A component that displays a list of forms with filtering, search, and action capabilities.

### Summary <a href="#summary" id="summary"></a>

The `FormList` component renders a grid of forms with search and tag filtering capabilities. It provides actions for viewing, editing, viewing submissions, and deleting forms. The component handles form loading and pagination automatically.

### Props <a href="#props" id="props"></a>

| Prop               | Type                            | Required | Description                                              |
| ------------------ | ------------------------------- | -------- | -------------------------------------------------------- |
| `onView`           | `() => void`                    | Yes      | Callback fired when a form is clicked to view            |
| `onEdit`           | `() => void`                    | Yes      | Callback fired when edit action is triggered             |
| `onViewSubmission` | `() => void`                    | Yes      | Callback fired when view submissions action is triggered |
| `onError`          | `(error: Error) => void`        | No       | Callback fired when an error occurs                      |
| `onDelete`         | `() => void`                    | No       | Callback fired after successful form deletion            |
| `components`       | `FormGridProps['components']`   | No       | Custom components for rendering form grid items          |
| `deleteComponents` | `FormDeleteProps['components']` | No       | Custom components for delete confirmation dialog         |
| `limit`            | `number`                        | No       | Maximum number of forms to load per page (default: 10)   |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { FormList } from '@formio/enterprise-form-builder-react';
import { useNavigate } from 'react-router-dom';

function FormsPage() {
  const navigate = useNavigate();

  return (
    <FormList
      onView={(formId) => navigate(`/forms/${formId}`)}
      onEdit={(formId) => navigate(`/forms/${formId}/edit`)}
      onViewSubmission={(formId) => navigate(`/forms/${formId}/submissions`)}
      onDelete={() => {
        console.log('Form deleted');
        // Refresh list or show notification
      }}
      onError={(error) => console.error('Error:', error)}
    />
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadforms)- Load forms list
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usedeleteform)- Delete forms
* [#formdelete](#formdelete "mention")- Delete confirmation component

## FormViewer

A component that displays a form for users to fill out and submit.

### Summary <a href="#summary" id="summary"></a>

The `FormViewer` component loads and renders a form by ID, allowing users to fill it out and submit it. It handles form loading, submission, and error states automatically.

### Props <a href="#props" id="props"></a>

| Prop            | Type                                              | Required | Description                                                          |
| --------------- | ------------------------------------------------- | -------- | -------------------------------------------------------------------- |
| `formId`        | `string`                                          | Yes      | ID of the form to display                                            |
| `onSubmit`      | `(submission: FormioSubmission) => Promise<void>` | No       | Callback fired when form is submitted                                |
| `onError`       | `(error: Error) => void`                          | No       | Callback fired when an error occurs                                  |
| `submitting`    | `boolean`                                         | No       | Whether the form is currently being submitted                        |
| `showInfoAlert` | `boolean`                                         | No       | Whether to show an info alert above the form (default: `true`)       |
| `className`     | `string`                                          | No       | Additional CSS classes to apply                                      |
| `options`       | `object`                                          | No       | Options to pass to the Form component (e.g., `noAlerts`, `readOnly`) |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { FormViewer } from '@formio/enterprise-form-builder-react';
import { useState } from 'react';

function FormFillPage({ formId }: { formId: string }) {
  const [submitting, setSubmitting] = useState(false);

  const handleSubmit = async (submission) => {
    setSubmitting(true);
    try {
      // Save submission or send to API
      console.log('Submission:', submission);
      // Navigate to success page
    } catch (error) {
      console.error('Error submitting:', error);
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <FormViewer
      formId={formId}
      onSubmit={handleSubmit}
      submitting={submitting}
      options={{ noAlerts: true }}
    />
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadform)- Load form data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usesavesubmission)- Save form submission

## UseForm

A component that displays a form with an existing submission for viewing or editing.

### Summary <a href="#summary" id="summary"></a>

The `UseForm` component loads both a form and a submission, then renders the form with the submission data pre-filled. It supports both view and edit modes.

### Props <a href="#props" id="props"></a>

| Prop             | Type                                        | Required | Description                                                                                   |
| ---------------- | ------------------------------------------- | -------- | --------------------------------------------------------------------------------------------- |
| `formId`         | `string`                                    | Yes      | ID of the form to display                                                                     |
| `submissionId`   | `string`                                    | Yes      | ID of the submission to load                                                                  |
| `submissionMode` | `'view' \| 'edit'`                          | No       | Mode for the form - 'view' renders read-only, 'edit' allows modifications (default: `'view'`) |
| `onSubmit`       | `(submission: Submission) => Promise<void>` | Yes      | Callback fired when form is submitted (in edit mode)                                          |
| `onError`        | `(error: Error) => void`                    | No       | Callback fired when an error occurs                                                           |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { UseForm } from '@formio/enterprise-form-builder-react';

function EditSubmissionPage({ 
  formId, 
  submissionId 
}: { 
  formId: string; 
  submissionId: string;
}) {
  const handleSubmit = async (submission) => {
    console.log('Submission updated:', submission);
    // Navigate back or show success message
  };

  return (
    <UseForm
      formId={formId}
      submissionId={submissionId}
      submissionMode="edit"
      onSubmit={handleSubmit}
      onError={(error) => console.error('Error:', error)}
    />
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadform)- Load form data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadsubmission)- Load submission data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usesavesubmission) - Save submission data

## SubmissionList

A component that displays a table of submissions for a specific form.

### Summary <a href="#summary" id="summary"></a>

The `SubmissionList` component renders a paginated table showing all submissions for a given form. It provides click handlers for viewing individual submissions and supports custom table components.

### Props <a href="#props" id="props"></a>

| Prop                | Type                             | Required | Description                                                                                          |
| ------------------- | -------------------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `formId`            | `string`                         | Yes      | ID of the form whose submissions to display                                                          |
| `limit`             | `number`                         | No       | Number of submissions per page (default: `10`)                                                       |
| `onSubmissionClick` | `(submissionId: string) => void` | No       | Callback fired when a submission row is clicked                                                      |
| `className`         | `string`                         | No       | Additional CSS classes to apply                                                                      |
| `tableComponents`   | `object`                         | No       | Custom components for rendering table elements (Container, TableContainer, TableHeadContainer, etc.) |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { SubmissionList } from '@formio/enterprise-form-builder-react';
import { useNavigate } from 'react-router-dom';

function SubmissionsPage({ formId }: { formId: string }) {
  const navigate = useNavigate();

  return (
    <SubmissionList
      formId={formId}
      limit={20}
      onSubmissionClick={(submissionId) => {
        navigate(`/forms/${formId}/submissions/${submissionId}`);
      }}
    />
  );
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [`SubmissionViewer`](#submissionviewer) - View individual submissions

## SubmissionViewer

A component that displays a submission with options to view, edit, or delete it.

### Summary <a href="#summary" id="summary"></a>

The `SubmissionViewer` component loads and displays a submission with a header containing action buttons. It supports viewing, editing, and deleting submissions, with different modes for each operation.

### Props <a href="#props" id="props"></a>

| Prop           | Type                                              | Required | Description                                                      |
| -------------- | ------------------------------------------------- | -------- | ---------------------------------------------------------------- |
| `formId`       | `string`                                          | Yes      | ID of the form the submission belongs to                         |
| `submissionId` | `string`                                          | Yes      | ID of the submission to display                                  |
| `onSave`       | `(submission: FormioSubmission) => Promise<void>` | No       | Callback fired when submission is saved (in edit mode)           |
| `onCancel`     | `() => void`                                      | No       | Callback fired when cancel action is triggered                   |
| `onBack`       | `() => void`                                      | No       | Callback fired when back button is clicked                       |
| `onError`      | `(error: Error) => void`                          | No       | Callback fired when an error occurs                              |
| `className`    | `string`                                          | No       | Additional CSS classes to apply                                  |
| `showHeader`   | `boolean`                                         | No       | Whether to show the header with action buttons (default: `true`) |
| `formTitle`    | `string`                                          | No       | Title of the form to display in the header                       |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { SubmissionViewer } from '@formio/enterprise-form-builder-react';
import { useNavigate } from 'react-router-dom';

function ViewSubmissionPage({ 
  formId, 
  submissionId 
}: { 
  formId: string; 
  submissionId: string;
}) {
  const navigate = useNavigate();

  const handleSave = async (submission) => {
    console.log('Submission saved:', submission);
    navigate(`/forms/${formId}/submissions`);
  };

  const handleBack = () => {
    navigate(`/forms/${formId}/submissions`);
  };

  return (
    <SubmissionViewer
      formId={formId}
      submissionId={submissionId}
      onSave={handleSave}
      onBack={handleBack}
      onError={(error) => console.error('Error:', error)}
      formTitle="My Form"
    />
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadsubmission)- Load submission data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usesavesubmission)- Save submission data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usedeletesubmission)- Delete submission component

## FormDelete

A component that provides a confirmation dialog for deleting a form.

### Summary <a href="#summary" id="summary"></a>

The `FormDelete` component renders a confirmation dialog with customizable components for the message and action buttons. It handles the deletion process and provides callbacks for success and cancellation.

### Props <a href="#props" id="props"></a>

| Prop              | Type                         | Required | Description                                             |
| ----------------- | ---------------------------- | -------- | ------------------------------------------------------- |
| `form`            | `FormType & { _id: string }` | Yes      | The form object to delete (must include `_id`)          |
| `onDeleteSuccess` | `() => void`                 | No       | Callback fired when deletion is successful              |
| `onCancel`        | `() => void`                 | No       | Callback fired when deletion is cancelled               |
| `components`      | `object`                     | No       | Custom components for rendering the confirmation dialog |

### Custom Components <a href="#custom-components" id="custom-components"></a>

The `components` prop accepts an object with optional custom components:

* `ConfirmationDialog`: Container component for the dialog
* `ConfirmationMessage`: Component that displays the confirmation message
* `ConfirmationButtons`: Component that renders the action buttons

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { FormDelete } from '@formio/enterprise-form-builder-react';

function DeleteFormModal({ form, onClose, onDeleted }) {
  return (
    <div className="modal show">
      <div className="modal-dialog">
        <div className="modal-content">
          <div className="modal-body">
            <FormDelete
              form={form}
              onDeleteSuccess={() => {
                onDeleted();
                onClose();
              }}
              onCancel={onClose}
            />
          </div>
        </div>
      </div>
    </div>
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usedeleteform)- Delete form functionality

## DeleteSubmission

A component that provides a confirmation dialog for deleting a submission.

### Summary <a href="#summary" id="summary"></a>

The `DeleteSubmission` component renders a simple confirmation dialog for deleting a submission. It handles the deletion process and provides callbacks for success, cancellation, and errors.

### Props <a href="#props" id="props"></a>

| Prop           | Type                      | Required | Description                                                                                          |
| -------------- | ------------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `formId`       | `string`                  | Yes      | ID of the form the submission belongs to                                                             |
| `submissionId` | `string`                  | Yes      | ID of the submission to delete                                                                       |
| `onCancel`     | `() => void`              | No       | Callback fired when deletion is cancelled                                                            |
| `onDeleted`    | `() => void`              | No       | Callback fired when deletion is successful                                                           |
| `onError`      | `(error: string) => void` | No       | Callback fired when an error occurs                                                                  |
| `title`        | `string`                  | No       | Custom title for the confirmation dialog (default: `'Are you sure you wish to delete this record?'`) |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { DeleteSubmission } from '@formio/enterprise-form-builder-react';

function DeleteSubmissionModal({ 
  formId, 
  submissionId, 
  onClose, 
  onDeleted 
}) {
  return (
    <div className="modal show">
      <div className="modal-dialog">
        <div className="modal-content">
          <div className="modal-body">
            <DeleteSubmission
              formId={formId}
              submissionId={submissionId}
              onDeleted={() => {
                onDeleted();
                onClose();
              }}
              onCancel={onClose}
              onError={(error) => console.error('Delete error:', error)}
            />
          </div>
        </div>
      </div>
    </div>
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usedeletesubmission) - Delete submission functionality

## FormSettings

A component that provides a form for editing form metadata (title, name, path, tags) and includes a delete form option.

### Summary <a href="#summary" id="summary"></a>

The `FormSettings` component renders a form for editing form settings and includes a "Danger Zone" section with a delete form button. It handles loading, saving, and error states automatically.

### Props <a href="#props" id="props"></a>

| Prop                 | Type                       | Required | Description                                         |
| -------------------- | -------------------------- | -------- | --------------------------------------------------- |
| `formId`             | `string`                   | No       | ID of the form to edit settings for                 |
| `Loading`            | `ReactNode`                | No       | Custom loading component to display while loading   |
| `onSaveSettingsForm` | `(form: FormType) => void` | No       | Callback fired when settings are successfully saved |
| `onError`            | `(error: Error) => void`   | No       | Callback fired when an error occurs                 |
| `onFormDelete`       | `() => void`               | No       | Callback fired when form is successfully deleted    |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { FormSettings } from '@formio/enterprise-form-builder-react';

function SettingsPage({ formId }: { formId: string }) {
  const handleSave = (form) => {
    console.log('Settings saved:', form);
    // Show success notification
  };

  const handleDelete = () => {
    console.log('Form deleted');
    // Navigate to form list
  };

  return (
    <FormSettings
      formId={formId}
      onSaveSettingsForm={handleSave}
      onFormDelete={handleDelete}
      onError={(error) => console.error('Error:', error)}
    />
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useloadform)- Load form data
* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#usedeleteform) - Save form settings
* [#formdelete](#formdelete "mention") - Delete form component


# React Context Provider

EnterpriseFormBuilderProvider is React context provider that initializes the Enterprise Form Builder Module environment and provides access to Form.io project configuration, license key, and authentication state.

### Summary <a href="#summary" id="summary"></a>

The `EnterpriseFormBuilderProvider` wraps your application and provides essential context for all enterprise form builder components and hooks. It automatically loads project information, roles, and sets up the Form.io license key. This provider must be used within a `FormioProvider` from `@formio/react`.

### Props <a href="#props" id="props"></a>

| Prop         | Type        | Required | Description                                                        |
| ------------ | ----------- | -------- | ------------------------------------------------------------------ |
| `licenseKey` | `string`    | Yes      | Your Form.io enterprise license key                                |
| `tag`        | `string`    | Yes      | Tag used to filter forms and resources                             |
| `children`   | `ReactNode` | Yes      | Child components that will have access to the form builder context |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { EnterpriseFormBuilderProvider } from '@formio/enterprise-form-builder-react';
import { FormioProvider } from '@formio/react';

function App() {
  return (
    <FormioProvider 
      projectUrl="https://your-project.form.io" 
      baseUrl="https://your-project.form.io"
    >
      <EnterpriseFormBuilderProvider 
        licenseKey="your-license-key"
        tag="common"
      >
        {/* Your application components */}
      </EnterpriseFormBuilderProvider>
    </FormioProvider>
  );
}
```

### Related Hooks <a href="#related-hooks" id="related-hooks"></a>

* [React Hook Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-hook-reference#useenterpriseformbuilder) - Access the provider context


# React Hook Reference

The following React Hooks are available:

* [useEnterpriseFormBuilder](#useenterpriseformbuilder) - Access the enterprise form builder context
* [useLoadForm](#useloadform) - Load a single form by ID
* [useLoadForms](#useloadforms) - Load multiple forms with optional query parameters
* [useSaveForm](#usesaveform) - Save forms with optional conflict resolution
* [useDeleteForm](#usedeleteform) - Delete a form by ID
* [useLoadSubmission](#useloadsubmission) - Load a single submission by form ID and submission ID
* [useSaveSubmission](#usesavesubmission) - Save a submission
* [useDeleteSubmission](#usedeletesubmission) - Delete a submission
* [useLoadProject](#useloadproject) - Load Form.io project information

## useEnterpriseFormBuilder

A hook that provides access to the enterprise form builder context.

### Summary <a href="#summary" id="summary"></a>

The `useEnterpriseFormBuilder` hook returns the context value from `EnterpriseFormBuilderProvider`, including project information, Form.io instance, license key, roles, and a helper function for getting builder options.

### Returns <a href="#returns" id="returns"></a>

| Property            | Type                                   | Description                                        |
| ------------------- | -------------------------------------- | -------------------------------------------------- |
| `licenseKey`        | `string`                               | The enterprise license key                         |
| `tag`               | `string`                               | The tag used for filtering forms                   |
| `project`           | `any`                                  | The Form.io project object                         |
| `roles`             | `Record<string, any>`                  | User roles from the project                        |
| `Formio`            | `any`                                  | The Form.io class/constructor                      |
| `projectUrl`        | `string`                               | The project URL                                    |
| `isAuthenticated`   | `boolean`                              | Whether the user is authenticated                  |
| `error`             | `string \| null`                       | Any error that occurred loading the project        |
| `getBuilderOptions` | `(displayType: FormDisplay) => object` | Function to get builder options for a display type |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useEnterpriseFormBuilder } from '@formio/enterprise-form-builder-react';

function MyComponent() {
  const { 
    project, 
    Formio, 
    projectUrl, 
    getBuilderOptions 
  } = useEnterpriseFormBuilder();

  const builderOptions = getBuilderOptions('form');

  // Use the context values...
}
```

### Related <a href="#related" id="related"></a>

* [`EnterpriseFormBuilderProvider`](/dev/enterprise-form-builder-module/application-integration/react-applications/react-context-provider) - Provider that supplies this context

## useLoadForm

A hook for loading a single form by ID.

### Summary <a href="#summary" id="summary"></a>

The `useLoadForm` hook provides functionality to load a form by its ID. It manages loading and error states automatically.

### Returns <a href="#returns" id="returns"></a>

| Property   | Type                                | Description                                |
| ---------- | ----------------------------------- | ------------------------------------------ |
| `loadForm` | `(formId: string) => Promise<void>` | Function to load a form by ID              |
| `form`     | `Form \| null`                      | The loaded form object                     |
| `loading`  | `boolean`                           | Whether the form is currently being loaded |
| `error`    | `string \| null`                    | Any error that occurred loading the form   |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useLoadForm } from '@formio/enterprise-form-builder-react';
import { useEffect } from 'react';

function FormDetails({ formId }: { formId: string }) {
  const { loadForm, form, loading, error } = useLoadForm();

  useEffect(() => {
    loadForm(formId);
  }, [formId, loadForm]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!form) return <div>Form not found</div>;

  return <div>{form.title}</div>;
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#createforms)- Form builder component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#formviewer)- Form display component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#useform)- Form with submission component

## useLoadForms

A hook for loading multiple forms with optional query parameters.

### Summary <a href="#summary" id="summary"></a>

The `useLoadForms` hook provides functionality to load a list of forms. It supports query parameters for filtering, pagination, and sorting.

### Returns <a href="#returns" id="returns"></a>

| Property    | Type                                                     | Description                                           |
| ----------- | -------------------------------------------------------- | ----------------------------------------------------- |
| `loadForms` | `(queryParams?: Record<string, any>) => Promise<Form[]>` | Function to load forms with optional query parameters |
| `forms`     | `Form[] \| null`                                         | The loaded forms array                                |
| `loading`   | `boolean`                                                | Whether forms are currently being loaded              |
| `error`     | `string \| null`                                         | Any error that occurred loading forms                 |

### Query Parameters <a href="#query-parameters" id="query-parameters"></a>

The `loadForms` function accepts query parameters such as:

* `limit`: Number of forms to return (default: 10)
* `skip`: Number of forms to skip (for pagination)
* `tags`: Array of tags to filter by
* `type`: Form type (default: "form")

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useLoadForms } from '@formio/enterprise-form-builder-react';
import { useEffect } from 'react';

function FormsList() {
  const { loadForms, forms, loading, error } = useLoadForms();

  useEffect(() => {
    loadForms({ limit: 20, tags: ['common'] });
  }, [loadForms]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <ul>
      {forms?.map(form => (
        <li key={form._id}>{form.title}</li>
      ))}
    </ul>
  );
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#formlist)- Form list display component

## useSaveForm

A hook for saving forms with optional conflict resolution.

### Summary <a href="#summary" id="summary"></a>

The `useSaveForm` hook provides functionality to save a form. It supports conflict resolution by merging changes when a conflict is detected.

### Returns <a href="#returns" id="returns"></a>

| Property     | Type                                                            | Description                                                           |
| ------------ | --------------------------------------------------------------- | --------------------------------------------------------------------- |
| `saveForm`   | `(formData: FormType, changes?: FormChange[]) => Promise<Form>` | Function to save a form with optional changes for conflict resolution |
| `savedForm`  | `Form \| null`                                                  | The saved form object                                                 |
| `loading`    | `boolean`                                                       | Whether the form is currently being saved                             |
| `error`      | `string \| null`                                                | Any error that occurred saving the form                               |
| `clearError` | `() => void`                                                    | Function to clear the error state                                     |

### Arguments <a href="#arguments" id="arguments"></a>

* `formData`: The form object to save
* `changes`: Optional array of `FormChange` objects for conflict resolution. If provided and a conflict occurs, the hook will attempt to merge changes automatically.

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useSaveForm } from '@formio/enterprise-form-builder-react';

function SaveFormButton({ form }) {
  const { saveForm, loading, error } = useSaveForm();

  const handleSave = async () => {
    try {
      const saved = await saveForm(form);
      console.log('Form saved:', saved);
    } catch (err) {
      console.error('Save failed:', err);
    }
  };

  return (
    <button onClick={handleSave} disabled={loading}>
      {loading ? 'Saving...' : 'Save Form'}
    </button>
  );
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#createforms) - Form builder component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#formsettings)- Form settings component

## useDeleteForm

A hook for deleting a form.

### Summary

The `useDeleteForm` hook provides functionality to delete a form by its ID. It manages loading, error, and success states automatically.

### Returns

| Property     | Type                                               | Description                               |
| ------------ | -------------------------------------------------- | ----------------------------------------- |
| `deleteForm` | `(options: DeleteFormOptions) => Promise<boolean>` | Function to delete a form                 |
| `loading`    | `boolean`                                          | Whether the deletion is in progress       |
| `error`      | `string \| null`                                   | Any error that occurred deleting the form |
| `success`    | `boolean`                                          | Whether the deletion was successful       |

### Arguments

The `deleteForm` function accepts an object with:

* `formId`: The ID of the form to delete

### Usage Example

```tsx
import { useDeleteForm } from '@formio/enterprise-form-builder-react';

function DeleteFormButton({ formId }: { formId: string }) {
  const { deleteForm, loading, error, success } = useDeleteForm();

  const handleDelete = async () => {
    await deleteForm({ formId });
  };

  if (success) return <div>Form deleted successfully!</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <button onClick={handleDelete} disabled={loading}>
      {loading ? 'Deleting...' : 'Delete Form'}
    </button>
  );
}
```

### Related Components

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#formdelete)- Delete confirmation component

## useLoadSubmission

A hook for loading a single submission by form ID and submission ID.

### Summary <a href="#summary" id="summary"></a>

The `useLoadSubmission` hook provides functionality to load a submission. It manages loading and error states automatically.

### Returns <a href="#returns" id="returns"></a>

| Property         | Type                                                      | Description                                      |
| ---------------- | --------------------------------------------------------- | ------------------------------------------------ |
| `loadSubmission` | `(formId: string, submissionId: string) => Promise<void>` | Function to load a submission                    |
| `submission`     | `Submission \| null`                                      | The loaded submission object                     |
| `loading`        | `boolean`                                                 | Whether the submission is currently being loaded |
| `error`          | `string \| null`                                          | Any error that occurred loading the submission   |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useLoadSubmission } from '@formio/enterprise-form-builder-react';
import { useEffect } from 'react';

function SubmissionDetails({ 
  formId, 
  submissionId 
}: { 
  formId: string; 
  submissionId: string;
}) {
  const { loadSubmission, submission, loading, error } = useLoadSubmission();

  useEffect(() => {
    loadSubmission(formId, submissionId);
  }, [formId, submissionId, loadSubmission]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!submission) return <div>Submission not found</div>;

  return <div>{JSON.stringify(submission.data)}</div>;
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#submissionviewer)- Submission display component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#useform) - Form with submission component

## useSaveSubmission

A hook for saving a submission.

### Summary <a href="#summary" id="summary"></a>

The `useSaveSubmission` hook provides functionality to save a submission. It manages loading and error states automatically.

### Returns <a href="#returns" id="returns"></a>

| Property         | Type                                                        | Description                                     |
| ---------------- | ----------------------------------------------------------- | ----------------------------------------------- |
| `saveSubmission` | `(formId: string, submission: Submission) => Promise<void>` | Function to save a submission                   |
| `loading`        | `boolean`                                                   | Whether the submission is currently being saved |
| `error`          | `string \| null`                                            | Any error that occurred saving the submission   |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useSaveSubmission } from '@formio/enterprise-form-builder-react';

function SaveSubmissionButton({ 
  formId, 
  submission 
}: { 
  formId: string; 
  submission: Submission;
}) {
  const { saveSubmission, loading, error } = useSaveSubmission();

  const handleSave = async () => {
    try {
      await saveSubmission(formId, submission);
      console.log('Submission saved');
    } catch (err) {
      console.error('Save failed:', err);
    }
  };

  return (
    <button onClick={handleSave} disabled={loading}>
      {loading ? 'Saving...' : 'Save Submission'}
    </button>
  );
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#submissionviewer)- Submission display component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#useform)- Form with submission component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#formviewer) - Form display component

## useDeleteSubmission

A hook for deleting a submission.

### Summary <a href="#summary" id="summary"></a>

The `useDeleteSubmission` hook provides functionality to delete a submission. It manages loading and error states automatically.

### Returns <a href="#returns" id="returns"></a>

| Property           | Type                                                        | Description                                     |
| ------------------ | ----------------------------------------------------------- | ----------------------------------------------- |
| `deleteSubmission` | `(formId: string, submission: Submission) => Promise<void>` | Function to delete a submission                 |
| `loading`          | `boolean`                                                   | Whether the deletion is in progress             |
| `error`            | `string \| null`                                            | Any error that occurred deleting the submission |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useDeleteSubmission } from '@formio/enterprise-form-builder-react';

function DeleteSubmissionButton({ 
  formId, 
  submission 
}: { 
  formId: string; 
  submission: Submission;
}) {
  const { deleteSubmission, loading, error } = useDeleteSubmission();

  const handleDelete = async () => {
    try {
      await deleteSubmission(formId, submission);
      console.log('Submission deleted');
    } catch (err) {
      console.error('Delete failed:', err);
    }
  };

  return (
    <button onClick={handleDelete} disabled={loading}>
      {loading ? 'Deleting...' : 'Delete Submission'}
    </button>
  );
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#formdelete)- Delete confirmation component
* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#submissionviewer)- Submission display component

## useLoadProject

A hook for loading project information.

### Summary <a href="#summary" id="summary"></a>

The `useLoadProject` hook provides functionality to load the Form.io project information. It manages loading and error states automatically.

### Returns <a href="#returns" id="returns"></a>

| Property      | Type                  | Description                                   |
| ------------- | --------------------- | --------------------------------------------- |
| `loadProject` | `() => Promise<void>` | Function to load project information          |
| `project`     | `any`                 | The loaded project object                     |
| `loading`     | `boolean`             | Whether the project is currently being loaded |
| `error`       | `string \| null`      | Any error that occurred loading the project   |

### Usage Example <a href="#usage-example" id="usage-example"></a>

```tsx
import { useLoadProject } from '@formio/enterprise-form-builder-react';
import { useEffect } from 'react';

function ProjectInfo() {
  const { loadProject, project, loading, error } = useLoadProject();

  useEffect(() => {
    loadProject();
  }, [loadProject]);

  if (loading) return <div>Loading project...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!project) return null;

  return <div>Project: {project.title}</div>;
}
```

### Related Components <a href="#related-components" id="related-components"></a>

* [React Component Reference](/dev/enterprise-form-builder-module/application-integration/react-applications/react-component-reference#createforms)- Form builder component


# Custom Components

Describes the process of building and creating a Custom Form Component.

## Introduction

One of the more powerful features of the Form.io platform is the ability to create custom form components. Creating a custom component involves extending a Base class of the component that is "closest" to the implementation you desire, and then overriding methods or introducing new methods that will implement the custom logic. All out-of-the-box components within the Form.io platform also use this same pattern, presenting a multitude of examples by inspecting how the base components for the Form.io renderer are implemented. Here is the link to all of the existing components for the Form.io renderer.

{% embed url="<https://github.com/formio/formio.js/tree/master/src/components>" %}

As shown, the implementation of any component involves extending a base class and then creating your own implementation on top of those base classes.

In order to create quality components, it is important to understand the critical methods used to define a new component. They are as follows:

## Extending Components

Every custom component will derive from a base class, whose behavior is closest to the behavior of the component you wish to create. It is possible to extend any other component within the Form.io renderer and a list of all of these components and their classes can be found @ <https://github.com/formio/formio.js/tree/master/src/components>

Because of this, the first task in building a custom component is to determine which component most closely resembles the behavior and data model of the component you are looking to achieve. For example, to build a multi-button select component, it may be best to start with a Radio component since it most closely resembles the behavior of the component you wish to create.

If you are unsure, then it is also fine to derive from the "core" components which serve as the base for all other components within the renderer. These core components are as follows:

### Core Components

| Class      | Extends    | Description                                                                                                          |
| ---------- | ---------- | -------------------------------------------------------------------------------------------------------------------- |
| Component  | Element    | Base component class                                                                                                 |
| Field      | Component  | Component that derives from Component class that implements a "field" render template                                |
| Multivalue | Field      | A component that is able to implement the "multiple" configuration allowing for multiple inputs for this field type. |
| Input      | Multivalue | A component type that implements an HTML value input.                                                                |

Each of the components can be extended by first referencing them from the `Components.components` object, and then extending them as follows.

```javascript
const Input = Formio.Components.components.input;
class MyInput extends Input {
  ...
  ...
}
```

For the most generic components, it is fine to derive from "Component", but in most value components, you may wish to derive from the Input component.

## Component Methods

Once you derive from a base component, the next step is to define methods that either override base behavior or introduce new behavior into the component class. It is recommended to look at the source code of your "base" component and the classes that it extends to understand what methods you have available to you, but the majority of all behavior can be achieved by implementing some of the following methods.

```javascript
const Input = Formio.Components.components.input;

class MyComponent extends Input {
    /**
     * This is the default schema of your custom component. It will "derive"
     * from the base class "schema" and extend it with its default JSON schema
     * properties. The most important are "type" which will be your component
     * type when defining new components.
     *
     * @param extend - This allows classes deriving from this component to 
     *                 override the schema of the overridden class.
     */
    static schema(...extend) {
        return Input.schema({
            type: 'mycomp',
            label: 'My Component',
            key: 'mycomp',
        });
    }
    
    /**
     * This is the Form Builder information on how this component should show
     * up within the form builder. The "title" is the label that will be given
     * to the button to drag-and-drop on the buidler. The "icon" is the font awesome
     * icon that will show next to it, the "group" is the component group where
     * this component will show up, and the weight is the position within that
     * group where it will be shown. The "schema" field is used as the default
     * JSON schema of the component when it is dragged onto the form.
     */
    static get builderInfo() {
        return {
          title: 'My Component',
          icon: 'terminal',
          group: 'basic',
          documentation: '/userguide/#textfield',
          weight: 0,
          schema: MyComponent.schema()
        };
    }
    
    /**
     * Called when the component has been instantiated. This is useful to define
     * default instance variable values.
     *
     * @param component - The JSON representation of the component created.
     * @param options - The global options for the renderer
     * @param data - The contextual data object (model) used for this component.
     */
    constructor(component, options, data) {
        super(component, options, data);
    }
    
    /**
     * Called immediately after the component has been instantiated to initialize
     * the component.
     */
    init() {
        super.init();
    }
    
    /**
     * For Input based components, this returns the <input> attributes that should
     * be added to the input elements of the component. This is useful if you wish
     * to alter the "name" and "class" attributes on the <input> elements created
     * within this component.
     *
     * @return - A JSON object that is the attribute information to be added to the
     *           input element of a component.
     */
    get inputInfo() {
        const info = super.inputInfo;
        return info;
    }
    
    /**
     * This method is used to render a component as an HTML string. This method uses
     * the template system (see Form Templates documentation) to take a template
     * and then render this as an HTML string.
     *
     * @param content - Important for nested components that receive the "contents"
     *                  of their children as an HTML string that should be injected
     *                  in the {{ content }} token of the template.
     *
     * @return - An HTML string of this component.
     */
    render(content) {
        return super.render('<div ref="customRef">This is a custom component!</div>');
    }
    
    /**
     * The attach method is called after "render" which takes the rendered contents
     * from the render method (which are by this point already added to the DOM), and
     * then "attach" this component logic to that html. This is where you would load
     * any references within your templates (which use the "ref" attribute) to assign
     * them to the "this.refs" component variable (see comment below).
     *
     * @param - The parent DOM HtmlElement that contains the component template.
     *
     * @return - A Promise that will resolve when the component has completed the
     *           attach phase.
     */
    attach(element) {
        /**
         * This method will look for an element that has the 'ref="customRef"' as an
         * attribute (like <div ref="customRef"></div>) and then assign that DOM
         * element to the variable "this.refs". After this method is executed, the
         * following will point to the DOM element of that reference.
         *
         * this.refs.customRef
         *
         * For DOM elements that have multiple in the component, you would make this
         * say 'customRef: "multiple"' which would then turn "this.refs.customRef" into
         * an array of DOM elements.
         */
        this.loadRefs(element, {
          customRef: 'single',
        });
        
        /**
         * It is common to attach events to your "references" within your template.
         * This can be done with the "addEventListener" method and send the template
         * reference to that object.
         */
        this.addEventListener(this.refs.customRef, 'click', () => {
            console.log('Custom Ref has been clicked!!!');        
        });
        return super.attach(element);
    }
    
    /**
     * Called when the component has been detached. This is where you would destroy
     * any other instance variables to free up memory. Any event registered with
     * "addEventListener" will automatically be detached so no need to remove them
     * here. 
     *
     * @return - A Promise that resolves when this component is done detaching.
     */
    detach() {
        return super.detach();
    }
 
    /**
     * Called when the component has been completely "destroyed" or removed form the
     * renderer.
     *
     * @return - A Promise that resolves when this component is done being destroyed.
     */
    destroy() {
        return super.destroy();
    }
 
    /**
     * A very useful method that will take the values being passed into this component
     * and convert them into the "standard" or normalized value. For exmample, this
     * could be used to convert a string into a boolean, or even a Date type.
     *
     * @param value - The value that is being passed into the "setValueAt" method to normalize.
     * @param flags - Change propogation flags that are being used to control behavior of the
     *                change proogation logic.
     *
     * @return - The "normalized" value of this component.
     */
    normalizeValue(value, flags = {}) {
        return super.normalizeValue(value, flags);
    }
    
    /**
     * Returns the value of the "view" data for this component.
     *
     * @return - The value for this whole component.
     */
    getValue() {
        return super.getValue();
    }
    
    /**
     * Much like "getValue", but this handles retrieving the value of a single index
     * when the "multiple" flag is used within the component (which allows them to add
     * multiple values). This turns a single value into an array of values, and this
     * method provides access to a certain index value.
     *
     * @param index - The index within the array of values (from the multiple flag) 
     *                that is getting fetched.
     *
     * @return - The view data of this index.
     */
    getValueAt(index) {
        return super.getValueAt(index);
    }
    
    /**
     * Sets the value of both the data and view of the component (such as setting the
     * <input> value to the correct value of the data. This is most commonly used
     * externally to set the value and also see that value show up in the view of the
     * component. If you wish to only set the data of the component, like when you are
     * responding to an HMTL input event, then updateValue should be used instead since
     * it only sets the data value of the component and not the view. 
     *
     * @param value - The value that is being set for this component's data and view.
     * @param flags - Change propogation flags that are being used to control behavior of the
     *                change proogation logic.
     *
     * @return - Boolean indicating if the setValue changed the value or not.
     */
    setValue(value, flags = {}) {
        return super.setValue(value, flags);
    }
    
    /**
     * Sets the value for only this index of the component. This is useful when you have
     * the "multiple" flag set for this component and only wish to tell this component
     * how the value should be set on a per-row basis.
     *
     * @param index - The index within the value array that is being set.
     * @param value - The value at this index that is being set.
     * @param flags - Change propogation flags that are being used to control behavior of the
     *                change proogation logic.
     *
     * @return - Boolean indiciating if the setValue at this index was changed.
     */
    setValueAt(index, value, flags = {}) {
        return super.setValueAt(index, value, flags);
    }
    
    /**
     * Similar to setValue, except this does NOT update the "view" but only updates
     * the data model of the component.
     *
     * @param value - The value of the component being set.
     * @param flags - Change propogation flags that are being used to control behavior of the
     *                change proogation logic.
     *
     * @return - Boolean indicating if the updateValue changed the value or not.
     */
    updateValue(value, flags = {}) {
        return super.updateValue(...args);
    }
}
```

## Component Modules

Custom components can be registered with the renderer using a module that is also able to include a large number of components. An example of a module that implements some custom components is the [**Contributed Components**](https://github.com/formio/contrib) repo.

{% embed url="<https://github.com/formio/contrib>" %}

In this repo, you can see that each component is defined within the "components" folder as follows.

![](/files/WrxcRptergOX1xS22xP4)

These components can then be included in the module by creating an export of these components like so.

```javascript
import components from './components';
import templates from './templates';
export default {
  components,
  templates
};
```

### Using Custom Components in applications

Once these components are created as a module, they can then easily be added to the renderer using the `Formio.use` method as follows.

```javascript
import { Formio } from '@formio/js';
import YourModule from './yourmodule';
Formio.use(YourModule);
```

Once this is done, any new components that have been added to the renderer / builder will show up and can be used in a web form.

{% hint style="warning" %}
Custom components can be rendered during Submission PDF generation by using a custom PDF viewer.
{% endhint %}

## Custom Component Templates

You can create custom components using the same lifecycle methods.

An example can be found at <https://github.com/formio/contrib/blob/master/src/components/rating/Rating.js>

### Template References (refs)

With the form.io templating functionality, the underlying DOM structure can be very different, even entirely custom. Because of this, adding events to the DOM necessitates being able to find the right part of the DOM to add the events. In order to do this, the formio.js library uses `refs` to refer to parts of the DOM. These can then be selected regardless of where they are in the DOM.

When rendering a template, you can use the ref attribute to set a reference string. Then in the attach phase, you can get any DOM elements that have that ref, regardless of where they are. In order to facilitate this, formio.js has a "loadRefs" function that can find all the refs and adds them to `this.refs`.

```
import { Templates, Components, Component } from '@formio/js';

Templates.addTemplate('mytemplate', {
    form: (ctx) => `
<div>
  <div ref="myref">
    ${ctx.foo}
    <div ref="mychild">1</div>
    <div ref="mychild">2</div>
    <div ref="mychild">3</div>
  </div>
</div>
`
});

class MyComponent extends Component {
  init() {
    // Init tasks here.
  }

  render() {
    // By calling super.render, it wraps in component wrappers.
    return super.render(this.renderTemplate('mytemplate', {
        foo: 'bar',
        data: 'these are available in the template'
    }));
  }

  attach(element) {
    this.loadRefs(element, {
      myref: 'single',
      mychild: 'multiple',
    });

    this.refs.myref; // This will be either null or the div with "myref" set on it.
    this.refs.mychild; // This will be either null or an array of divs with "mychild" set on them.
  }

  detach() {
    // Called on redraw or rebuild. The opposite of attach.
  }

  destroy() {
    // Called on rebuild. The opposite of init.
  }
}

Components.addComponent('mycomponent', MyComponent);
```

### Layout component references

Layout components can contain other components within them including other components of the same type. For this reason, be careful with refs in layout components and be sure to append the component id to each key. This is so that loadRefs only selects the refs for that component and not any nested components.

## Examples

Below are code examples of different Custom Components that you can use in your application or as a foundation for building your own custom components.

Follow the link for a full list of Custom Components found within the Contrib Repository

{% embed url="<https://github.com/formio/contrib/tree/master/src/components>" %}

### CheckMatrix

Below is a code example for a custom component - Check Matrix. This component allows you to set up a grid of checkboxes where each box can be independently checked, with the data saved as a multi-dimensional array.

```javascript
/**
 * This file shows how to create a custom component.
 *
 * Get the base component class by referencing Formio.Components.components map.
 */
import { Formio, Components } from '@formio/js';
const FieldComponent = (Components as any).components.field;
import editForm from './CheckMatrix.form';

/**
 * Here we will derive from the base component which all Form.io form components derive from.
 *
 * @param component
 * @param options
 * @param data
 * @constructor
 */
export default class CheckMatrix extends (FieldComponent as any) {
  public checks: any[][];
  constructor(component, options, data) {
    super(component, options, data);
    this.checks = [];
  }

  static schema() {
    return FieldComponent.schema({
      type: 'checkmatrix',
      numRows: 3,
      numCols: 3
    });
  }

  public static editForm = editForm;

  static builderInfo = {
    title: 'Check Matrix',
    group: 'basic',
    icon: 'fa fa-table',
    weight: 70,
    documentation: 'http://help.form.io/userguide/#table',
    schema: CheckMatrix.schema()
  }

  get tableClass() {
    let tableClass = 'table ';
    ['striped', 'bordered', 'hover', 'condensed'].forEach((prop) => {
      if (this.component[prop]) {
        tableClass += `table-${prop} `;
      }
    });
    return tableClass;
  }

  get emptyValue() {
    return [];
  }

  public render() {
    return super.render(this.renderTemplate('checkmatrix', {
      tableClass: this.tableClass
    }));
  }

  refKey(i, j) {
    return `${this.component.key}-${i}-${j}`;
  }

  /**
   * After the html string has been mounted into the dom, the dom element is returned here. Use refs to find specific
   * elements to attach functionality to.
   *
   * @param element
   * @returns {Promise}
   */
  attach(element) {
    const refs = {};
    // Iterate through all cells and add refs.
    for (let i = 0; i < this.component.numRows; i++) {
      for (let j = 0; j < this.component.numCols; j++) {
        refs[this.refKey(i, j)] = 'single';
      }
    }

    // Load the references.
    this.loadRefs(element, refs);

    // Re-iterate through the refs and add event listeners.
    for (let i = 0; i < this.component.numRows; i++) {
      for (let j = 0; j < this.component.numCols; j++) {
        this.addEventListener(this.refs[this.refKey(i, j)], 'click', () => this.updateValue())
      }
    }

    // Allow basic component functionality to attach like field logic and tooltips.
    return super.attach(element);
  }

  /**
   * Get the value of the component from the dom elements.
   *
   * @returns {Array}
   */
  getValue() {
    const value = [];
    for (let i = 0; i < this.component.numRows; i++) {
      value[i] = [];
      for (let j = 0; j < this.component.numCols; j++) {
        if (this.refs.hasOwnProperty(this.refKey(i,j))) {
          value[i][j] = !!this.refs[this.refKey(i,j)].checked;
        }
      }
    }
    return value;
  }

  /**
   * Set the value of the component into the dom elements.
   *
   * @param value
   * @returns {boolean}
   */
  setValue(value) {
    if (!value) {
      return;
    }
    for (let i = 0; i < this.component.numRows; i++) {
      for (let j = 0; j < this.component.numCols; j++) {
        if (
          value.length > i &&
          value[i].length > j &&
          this.refs.hasOwnProperty(this.refKey(i,j))
        ) {
          const ref = this.refs[this.refKey(i,j)];
          const checked = value[i][j] ? 1 : 0;
          ref.value = checked;
          ref.checked = checked;
        }
      }
    }
  }
}

// Use the component.
Formio.use({
  components: {
    checkmatrix: CheckMatrix
  }
});
```

This component can now be rendered in both the builder and renderer as the following JSFiddle illustrates.

{% embed url="<https://jsfiddle.net/travistidwell/mur92q1d/>" %}

### Header Component

An example of custom component implementation would be to create a Custom Component called **Header** which will allow the configuration of one of the following `<h1>, <h2>, <h3> etc`

For this component, we will simply extend the HTML Element component which allows for dynamic HTML to be rendered within a form.

{% embed url="<https://github.com/formio/formio.js/blob/master/src/components/html/HTML.js>" %}

This example also shows how you can introduce changes to the Form Builder to introduce new configurations or make changes to other configurations.

Here is the code for a **Header** component

```javascript
// Get the HTMLComponent from the components listing.
const HTMLComponent = Formio.Components.components.htmlelement;

/**
 * Create a Header compoennt and extend from the HTMLComponent.
 */
class HeaderComponent extends HTMLComponent {
  /**
   * Define the default schema to change the type and tag and label. 
   */
  static schema(...extend) {
    return HTMLComponent.schema({
      label: 'Header',
      type: 'header',
      tag: 'h1'
    }, ...extend);
  }
  
  static get builderInfo() {
    return {
      title: 'Header',
      group: 'layout',
      icon: 'code',
      weight: 2,
      documentation: '/userguide/#html-element-component',
      schema: HeaderComponent.schema()
    };
  }
}

/**
 * Change the edit form to make the "tag" component a select dropdown
 * instead of a textfield so that they can only configure the "h2" fields.
 */
HeaderComponent.editForm = (...args) => {
  const editForm = HTMLComponent.editForm(...args);
  const tagComponent = Formio.Utils.getComponent(editForm.components, 'tag');
  tagComponent.type = 'select';
  tagComponent.dataSrc = 'values';
  tagComponent.data = {
    values: [
      {label: 'H1', value: 'h1'},
      {label: 'H2', value: 'h2'},
      {label: 'H3', value: 'h3'},
      {label: 'H4', value: 'h4'},
      {label: 'H5', value: 'h5'}
    ]
  };
  return editForm;
};

Formio.Components.addComponent('header', HeaderComponent);
```

This component can actually be tested by opening up the Form.io hosted portal @ <https://portal.form.io>, pasting the code within the console of the browser, and then pressing Enter. Then when you navigate to the form builder, you will see the following.

![](/files/hMbjKB5OWj836frodDa8)

![](/files/vH8fvYaRUxT7OGeWRsfq)


# Form Development


# Form Builder

Learn how to use the Form.io JavaScript form builder

## Introduction

The Form.io Form Builder is an extension on the Form Renderer that allows for dynamic drag-and-drop building of the forms that will be rendered within the Form Renderer. The purpose of the form builder is to serve as a front-end user interface that is able to visually create the JSON schemas that are needed to be rendered into the form. For this reason, it can be thought of as a glorified JSON schema builder, where each field dragged onto the form creates the JSON schema of that component as it is configured. The following diagram illustrates this relationship between the form builder interface and the JSON schema that is being created.

![Form.io Form Builder creating a JSON schema](/files/jyY9bTzIJHoLvegALzZq)

For a great interactive visual on how the Form.io Form Builder works, we highly recommend visiting the Form Builder Demo @ <https://formio.github.io/formio.js/app/builder> to visually see how building a form and configuring the components can modify the JSON of the form in real time.

## Embedding the Form Builder

One great benefit of the Form.io form builder is it can also be embedded into your application just like the form renderer. It is very similar to the form renderer, which just a few minor changes. First we will need to open up a new JSFiddle and input the following configurations.

Add the following **Resources.**

{% hint style="info" %}
The following CDN URLS hosts the **Form.io JavaScript library** and related resources. There are different CDN namespaces available for both the 4.x and 5.x renderers. Users who self-host the renderer can define custom URL formats and files to specify their preferred Form.io renderer version

Navigate to the following link for more information on [**Form.io CDNs**](https://help.form.io/dev/form-development/spaces/dE1To8ypyE1yhXEJ7QlD/pages/2ae5hrS2IA25reIexyXB#what-are-the-form.io-cdns)
{% endhint %}

**Formio.js 4x**

* `https://cdn.form.io/js/formio.full.min.js`
* `https://cdn.form.io/js/formio.form.min.css`
* `https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css`
* `https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css`

**Formio.js 5x**

* `https://cdn.form.io/js/formio.form.min.js`
* `https://cdn.form.io/js/formio.form.min.css`
* `https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css`
* `https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css`

Add the following **HTML**

```markup
<div id="builder"></div>
```

Add the following **JavaScript**.

```javascript
Formio.builder(document.getElementById('builder'));
```

Once you do this, you will then see your Form Builder show up in the result panel.

![Illustrates how the form builder can be embedded in an application](/files/dfhIgSEzdD0JuAtwciwe)

This is a fully functional form building interface, which you can see by checking out the following JSFiddle.

{% embed url="<https://jsfiddle.net/travistidwell/Lq9vgka4/>" %}

Let's now explore all the options you can use to customize the form builder interface.

## Form Builder SDK

In order to take advantage of the form builder, you need to understand all of the options available to you when working with the form builder interface. In all cases, the Form Builder is instantiated using the `Formio.Builder` method, which is defined as follows.

### `Formio.builder(element, [form], [options])`

This method creates a new Form Builder interface within your application, and the following parameters can be applied.

| Parameter          | Description                                                                                                         |
| ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| element            | The DOM element you would like to attach the form builder against.                                                  |
| form (optional)    | Either the "src" or the form JSON you would like to use as the default form that shows up in the builder interface. |
| options (optional) | See [Form Builder Options](#form-builder-options) section.                                                          |

As an example, the following will create a new form builder, and then auto populate it with the form defined.

```javascript
Formio.builder(document.getElementById('builder'), {
  components: [
    {
    	type: 'textfield',
      key: 'firstName',
      label: 'First Name'
    },
    {
    	type: 'textfield',
      key: 'lastName',
      label: 'Last Name'
    }
  ]
});
```

Which produces the following builder interface.

![](/files/LowKeebkCg2KRJdjyGLV)

The `Formio.Builder` method returns a promise that will resolve with the Form Builder instance, which can be used as follows.

```javascript
Formio.builder(document.getElementById('builder'), {
  components: [
    {
    	type: 'textfield',
      key: 'firstName',
      label: 'First Name'
    },
    {
    	type: 'textfield',
      key: 'lastName',
      label: 'Last Name'
    }
  ]
}).then((builder) => {

  // Here is the form builder instance.
  console.log(builder);
});
```

In a later section we will go through some of the methods that can be used on the builder instance that will further enable customizations of the form builder interface.

## Form Builder Options

The options of the form builder are passed as a JavaScript object to the `Formio.Builder` method like the following illustrates.

```javascript
Formio.builder(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
    disabled: ['email']
});
```

The following are a list of options that can be passed to the Form Builder instantiation method.

| Property                      | Description                                                                                                                                                     |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| disabled                      | An array of "keys" of components that should be disabled within the form builder. Example: `['firstName', 'lastName']`                                          |
| noNewEdit                     | Boolean (true) that makes it so that there is no modal that is shown when a component is dragged onto the form.                                                 |
| noDefaultSubmitButton         | Boolean (true) that will not show a submit button by default in the builder.                                                                                    |
| alwaysConfirmComponentRemoval | Boolean (true) that will make every component removal show a confirmation message if you are sure you wish to remove the component (like layout components do). |
| formConfig                    | Form configurations to apply forms being created. These configurations are added to the "config" property of the form object.                                   |
| resourceTag                   | The tag to use to query for the "Existing Resource Fields" section of the builder.                                                                              |
| editForm                      | Options to apply to the Edit Form which is the form that shows inside the modal when you edit a component.                                                      |
| language                      | The language of the builder.                                                                                                                                    |
| builder                       | See [**Builder Sidebar Configuration**](#builder-sidebar-configuration)                                                                                         |
| display                       | The type of builder to be rendered. Must be 'form' (for a WebForm class), 'wizard' (for a Wizard), or 'pdf' (for a PDF form).                                   |
| resourceFilter                | Filter the resources that appear in the builder's Existing Resource Fields.                                                                                     |
| noSource                      | Don't link the resource ID in the builder's Existing Resource Fields.                                                                                           |
| alwaysConfirmComponentRemoval | If set to true, removing a component will always show an alert confirming that you want to delete the component.                                                |
| language                      | The current language for the builder.                                                                                                                           |
| showFullJsonSchema            | Show a component's entire JSON schema.                                                                                                                          |

#### Builder Sidebar Configuration

These are the properties that can be set on the "builder" configuration option that is passed to the builder. This option is passed to the form builder like the following illustrates.

```javascript
Formio.builder(document.getElementById('formio'), {}, {
    builder: {
        ...
    }
});
```

The properties in this configuration allow for the manipulation of the Builder sidebar as well as control the default schemas and behaviors of the fields that are added to Form Builder. By default, this property has the following configuration.

```javascript
{
    resource: true, // Boolean to turn on or off "Existing Resource Fields" section
    basic: {
      title: 'Basic',
      weight: 0,
      default: true,
    },
    advanced: {
      title: 'Advanced',
      weight: 10
    },
    layout: {
      title: 'Layout',
      weight: 20
    },
    data: {
      title: 'Data',
      weight: 30
    },
    premium: {
      title: 'Premium',
      weight: 40
    }
}
```

Each of these sections can be turned off by simply adding a `false` for the value of that component.

For example, if we wish to turn off the Advanced, Premium, and Existing Resource Fields sections of the form builder sidebar, we could pass along the following configurations.

```javascript
Formio.builder(document.getElementById('builder'), {}, {
    builder: {
        resource: false,
        advanced: false,
        premium: false
    }
});
```

This configuration can also be used to add Pre-defined components to the builder.

#### Adding Pre-Defined Components

A pre-defined component is a component that you provide the JSON configuration up front and then allow an end-user to drag-and-drop that component onto a form. A good example of this would be if you wish to have defined fields, such as "First Name" "Last Name" and "Email", instead of the field types, such as "Text Field", that are provided by default. Pre-defined fields can be added to the form builder using the `builder` as the following illustrates.

```javascript
Formio.builder(document.getElementById('builder'), {}, {
    builder: {
        custom: {
            title: 'Pre-Defined Fields',
            weight: 10,
            components: {
                firstName: {
                    title: 'First Name',
                    key: 'firstName',
                    icon: 'terminal',
                    schema: {
                        label: 'First Name',
                        type: 'textfield',
                        key: 'firstName',
                        input: true
                    }
                },
                lastName: {
                    title: 'Last Name',
                    key: 'lastName',
                    icon: 'terminal',
                    schema: {
                      label: 'Last Name',
                      type: 'textfield',
                      key: 'lastName',
                      input: true
                    }
                },
                email: {
                    title: 'Email',
                    key: 'email',
                    icon: 'at',
                    schema: {
                        label: 'Email',
                        type: 'email',
                        key: 'email',
                        input: true
                    }
                },
                phoneNumber: {
                    title: 'Mobile Phone',
                    key: 'mobilePhone',
                    icon: 'phone-square',
                    schema: {
                        label: 'Mobile Phone',
                        type: 'phoneNumber',
                        key: 'mobilePhone',
                        input: true
                    }
                }
            }
        }
    }
});
```

The default schema for each of these fields is defined in the `schema` property of that component, which means that as the user drags-and-drops the field on to the form builder, this is the schema that will be used to default that field on the form. The following configuration produces the following form builder.

![](/files/BOO9aIy48exTEvQUg7Im)

## Events

The following form builder events are emitted from the form builder as the user is building forms.

| Event                     | Description                                                                           | Arguments                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| addComponent              | Triggered every time a component is added to the form via the builder drop operation. | <ul><li>info: The component information that was added to the form.</li><li>parent: The parent component information.</li><li>path: The component path for this dropped component</li><li>index: The index within the parent for this component.</li><li>isNew: Boolean to indicate if the component is "new" to the form. "false" means it was dragged and dropped from elsewhere on the form.</li></ul> |
| removeComponent           | Triggered when a component is removed by the form builder.                            | <ul><li>component: The component being removed.</li><li>schema: The component minified json schema</li><li>path: The component path for this dropped component</li><li>index: the index within the parent for this component.</li></ul>                                                                                                                                                                   |
| updateComponent           | Triggered when a component has been updated within the form builder                   | <ul><li>component: The component being updated.</li></ul>                                                                                                                                                                                                                                                                                                                                                 |
| builderFormValidityChange | Triggered when the builder highlights some fields as invalid                          | <ul><li>hasInvalidComps: Boolean if there are invalid components.</li></ul>                                                                                                                                                                                                                                                                                                                               |

## Overriding Behavior

Just like the Form Renderer, the form builder can also be overridden in a very similar way to what is described in the [Overriding Behavior](/dev/form-development/form-renderer#overriding-behavior) section of the Form Renderer documentation.

With the form builder, however, you can override the Component forms for each component by modifying the `editForm` property of that component. This property is a function that accepts other overrides and then returns the Form.io Form of that component edit form. As an example, the following will change the Text Fields edit form to ONLY contain the label.

```
Formio.Components.components.textfield.editForm = function() {
  return {
    components: [
      {
        type: 'textfield',
        key: 'label',
        label: 'Label'
      }
    ]
  };
};
```

It should be noted that the key of each of these components need to correlate to the property name of the Component JSON. So for example, if you wish to include a field for the Required property, you can use the following schema.

```
Formio.Components.components.textfield.editForm = function() {
  return {
    components: [
      {
        type: 'textfield',
        key: 'label',
        label: 'Label'
      },
      {
        type: 'checkbox',
        key: 'validate.required',
        label: 'Required'
      }
    ]
  };
}; 
```

With the same methods as described in the Overriding Form Renderer documentation, you can also modify the existing edit form using a method similar to the following.

```
var textFieldEditForm = Formio.Components.components.textfield.editForm;
Formio.Components.components.textfield.editForm = function() {
  var editForm = textFieldEditForm();
  
  // Make changes to the editForm here!
  
  return editForm;
};
```


# Form Renderer

A technical deep-dive into the powerful Form.io JavaScript Renderer

The Form Renderer is one of the most significant differences between the Form.io Platform and other form providers.

With the Form.io Platform, the Form Builder uses drag-and-drop components to create a JSON schema that defines how a form looks and functions. This JSON is then sent to the **Form Renderer**, which is directly embedded within an application, to display the form and capture inputs.\
This is in contrast to other solutions that render forms on a server (using technologies like PHP, .NET, Java, etc) and then send the rendered form HTML up to the browser to be used. This approach has significant limitations when used within a modern mobile-first web application.

Here is an image that illustrates how this rendering works within a mobile application.

![How the Form.io JavaScript Renderer works](/files/yxfUliwnosL3bAZVQMMd)

The library responsible for this rendering can be found on Github ([**https://github.com/formio/formio.js**](https://github.com/formio/formio.js)) and is also Open Source, so that any developer can fork and extend the functionalities provided by this library.

## Getting Started

The easiest way to understand the novel approach to form rendering is to step through working examples.

To start, first create a new Project within the Form.io Developer Portal (<https://portal.form.io>), and then create a new simple form that we will use to test out the JavaScript renderer. Here is just an example of what a basic form may look like.

![](/files/39tbdsVgE0MpB3Vbe9b6)

Use the link icon next to the Form name to copy the Form API URL path (circled in the picture above) and save this for later when we wish to render the form. Now that we have our form, we can test out how this form will be rendered.

To test our JavaScript Renderer, you can use one of many online web application editors. Two commonly used options are:

* JSFiddle - [**https://jsfiddle.net**](https://jsfiddle.net)
* CodePen - [**https://codepen.io**](https://codepen.io)

For this demonstration, use JSFiddle.

First add the following **Resources.**

{% hint style="info" %}
The following CDN URLS host the **Form.io JavaScript library** and related resources. There are different CDN namespaces available for both the 4.x and 5.x renderers. Users who self-host the renderer can define custom URL formats and files to specify their preferred Form.io renderer version

Navigate to the following link for more information on [**Form.io CDNs**](https://help.form.io/dev/form-development/spaces/dE1To8ypyE1yhXEJ7QlD/pages/2ae5hrS2IA25reIexyXB#what-are-the-form.io-cdns)
{% endhint %}

**Formio.js 4x**

* `https://cdn.form.io/js/formio.full.min.js`
* `https://cdn.form.io/js/formio.form.min.css`
* `https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css`

**Formio.js 5x**

* `https://cdn.form.io/js/formio.form.min.js`
* `https://cdn.form.io/js/formio.form.min.css`
* `https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css`

These urls are described as follows:

* formio.form.min.js - This is the minified JavaScript source code for the Form.io Renderer
* formio.form.min.css- This is the minified CSS style sheets for the Form.io Renderer
* bootstrap.min.css - This is the Bootstrap CSS Framework which Form.io uses to render forms.

The JSFiddle should now look like the following:

![](/files/-MblvS4vYF6Lmyg3Ts4C)

This is functionally the same as building an HTML application from scratch with the following HTML code.

```html
<!doctype html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.form.io/js/formio.form.min.css" crossorigin="anonymous">
  </head>
  <body>
    <script src="https://cdn.form.io/js/formio.form.min.js" crossorigin="anonymous"></script>
  </body>
</html>
```

Next, add a place to render the form.

Do this by adding a single `div` tag into the HTML region and then giving it an "id" to refer to it within the JavaScript initialization code (written later).\
Copy the following code into the HTML section of JSFiddle:

```html
<div id="formio"></div>
```

It should look like the following:

![](/files/-MblvS4vYF6Lmyg3Ts4C)

This is functionally equivalent to the raw HTML:

```html
<!doctype html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.form.io/js/formio.form.min.css" crossorigin="anonymous">
  </head>
  <body>
    <div id="formio"></div>
    <script src="https://cdn.form.io/js/formio.form.min.js" crossorigin="anonymous"></script>
  </body>
</html>
```

## Rendering Form URL

And now for the fun part: Use the Form.io JavaScript SDK to instantiate the form that was just built within the Form.io Portal.

Do this by writing the following code within the JavaScript section of the JSFiddle:

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform');
```

Where *myproject* in the sample code is replaced with the name of your project used in the Developer Portal, and *rendertest* is the name used for the form.

Note the following output when the application runs in JSFiddle:

![](/files/-MblvS4vYF6Lmyg3Ts4C)

Here is the JSFiddle link for you to try this yourself.

{% embed url="<https://jsfiddle.net/travistidwell/6uge153s/>" %}

{% hint style="info" %}
The Form.io renderer is very flexible and as such can be configured to achieve many different use cases. Because of this, we have built a dedicated application that is used to demonstrate many of the features that our form renderer has to offer. This can be found at the following url.

[Form.io Examples Application](https://formio.github.io/formio.js/app/examples/)
{% endhint %}

## Rendering Form JSON

In addition to rendering a URL, the form renderer can also be used to render simple JSON passed into the renderer like so.

```javascript
Formio.createForm(document.getElementById('formio'), {
  components: [
  	{
      type: 'textfield',
      key: 'firstName',
      label: 'First Name'
    },
    {
    	type: 'textfield',
      key: 'lastName',
      label: 'Last Name'
    },
    {
    	type: 'email',
      key: 'email',
      label: 'Email'
    },
    {
    	type: 'button',
      key: 'submit',
      label: 'Submit'
    }
  ]
});
```

Which will render the form as follows.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

If you wish to get the JSON of a form as you build it with the form builder, then we suggest that you check out the Form.io Builder Sandbox which can be found @ [**https://formio.github.io/formio.js/app/builder**](https://formio.github.io/formio.js/app/builder)

## Submission Data

Now that we have rendered a form, the next step will be to inject a submission into the form so that it will show data pre-populated within the form. One interesting thing to note about Form.io is that it completely separates the Form JSON from the Submission JSON and they are treated as separate JSON entities. Submission data will never be included as part of the form JSON. For example, the following Form JSON

```javascript
{
  "components": [
    {
      "type": "textfield",
      "key": "firstName",
      "label": "First Name"
    },
    {
      "type": "textfield",
      "key": "lastName",
      "label": "Last Name"
    }
  ]
}
```

will take the following submission data JSON.

```javascript
{
  "data": {
    "firstName": "Joe",
    "lastName": "Smith"
  }
}
```

There are a couple of things to note here.

1. The submission data for the form is contained within a "data" object.
2. The "keys" for the submission data is determined by the "key" property of each component within the form.

You can alter the data structure by using dot-notation in the Form JSON which will allow you to alter the data construct of the submission. For example, if you wish to include the firstName and lastName fields within a "customer" data object, you could do the following.

```javascript
{
  "components": [
    {
      "type": "textfield",
      "key": "customer.firstName",
      "label": "Customer First Name"
    },
    {
      "type": "textfield",
      "key": "customer.lastName",
      "label": "Customer Last Name"
    }
  ]
}
```

The dot-notation for the "keys" in this form tell the renderer to structure the submission as follows.

```javascript
{
  "data": {
    "customer": {
      "firstName": "Joe",
      "lastName": "Smith"
    }
  }
}
```

### Data Components

Another way to alter the submission data construct is to use any of the Data Components within a form. These are special components that are used to not only visually show the data being collected in a structured way, but will also change the data structure of the submissions being produced by the rendered form. For example, if you wish to produce the following submission data which is an array of children's first and last names, you can use the Data Grid component as follows.

```javascript
{
  "components": [
    {
      "type": "datagrid",
      "label": "Children",
      "key": "children",
      "components": [
        {
          "type": "textfield",
          "key": "firstName",
          "label": "First Name"
        },
        {
          "type": "textfield",
          "key": "lastName",
          "label": "Last Name"
        } 
      ]
    }
  ]
}
```

Produces the following submission JSON.

```javascript
{
  "data": {
    "children": [
      {
        "firstName": "Joe",
        "lastName": "Smith"
      },
      {
        "firstName": "Mary",
        "lastName": "Thompson"
    ]
  }
}
```

And for the Data Grid component, it looks like the following when being rendered.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

There are other kinds of data components as described as follows.

| Component  | Type      | Description                                                           |
| ---------- | --------- | --------------------------------------------------------------------- |
| Data Grid  | datagrid  | Spreadsheet UI that stores an array of objects                        |
| Edit Grid  | editgrid  | Table UI that stores an array of objects, with inline edit            |
| Data Map   | datamap   | Key-value pair where string key can be provided for dynamic values    |
| Data Table | datatable | Grid UI that stores an array of objects                               |
| Container  | container | Hidden container UI that stores components inside an isolated object. |
| Hidden     | hidden    | Hidden UI that can store any data value in any data structure.        |

## Rendering Submissions

In order to render a submission, you must first render the form and then set the form submission to the submission data you wish to render within the form. You can either render the form as JSON or as a form URL as described above and then the submission is set once the form is done rendering. As a simple example, you can provide the following to demonstrate how a submission can be rendered within a form.

```javascript
Formio.createForm(document.getElementById('formio'), {
  components: [
    {
      type: 'textfield',
      key: 'firstName',
      label: 'First Name'
    },
    {
      type: 'textfield',
      key: 'lastName',
      label: 'Last Name'
    }
  ]
}).then((form) => {
  form.submission = {
    data: {
      firstName: 'Joe',
      lastName: 'Smith'
    }
  };
});
```

Which will render as the following.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

You can also render the submissions from a Form URL as the following demonstrates.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform')
    .then((form) => {
        form.submission = {
            data: {
                firstName: 'Mary',
                lastName: 'Thompson',
                email: 'mary@example.com'
            }
        };
    });
```

which will render as follows.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

### Rendering Submission API URL

The last way to render a submission is to render the submission via the API endpoint of that submission. This Submission API is described as follows.

## Retrieve a form submission

<mark style="color:blue;">`GET`</mark> `https://forms.mysite.com/myproject/:formName/submission/:submissionId`

Retrieves a single submission within a form.

#### Path Parameters

| Name         | Type   | Description                                  |
| ------------ | ------ | -------------------------------------------- |
| formName     | string | The "alias" name of the form                 |
| submissionId | string | A valid MongoDb ID for the submission "\_id" |

{% tabs %}
{% tab title="200 An example response for a valid form submission." %}

```
{
  "_id": "5fc7c4082a992abe68b247b9",
  "owner": "5fc7beeb2a992abe68b2475c",
  "roles": [],
  "_vid": 0,
  "_fvid": 1,
  "state": "submitted",
  "data": {
    "firstName": "Joe",
    "lastName": "Smith",
    "email": "joe@example.com",
    "phoneNumber": "(123) 123-1234"
  },
  "access": [],
  "form": "5fc7c25a2a992abe68b247b4",
  "project": "5fc7befe2a992abe68b24765",
  "externalIds": [],
  "created": "2020-12-02T16:42:48.128Z",
  "modified": "2020-12-02T16:42:48.129Z"
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
In order to utilize this rendering correctly, you will need to ensure that the user you are authenticated as has access to this submission. You can authenticate a user by setting a valid JWT token within the "formioToken" localStorage variable of your application.
{% endhint %}

This URL can then be added to the renderer to render a complete form with submission as follows.

```javascript
Formio.createForm(
  document.getElementById('formio'),
  'https://forms.mysite.com/myproject/wizard/submission/5a542c9e2a40bf0001e0f8a9'
);
```

Which will render the form and submission as follows.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

## Controlling the Form with JavaScript

One of the most powerful concepts of Form.io rendered forms is that you can control the rendered form using JavaScript. In most cases, this is done within the section of code that executes once the form has finished rendering. This is commonly referred to as the "Form Controller" section of the form renderer and can be seen as follows.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform')
    .then((form) => {
        // This section of code is the "Form Controller"
    });
```

The variable that is passed to this function can be called whatever you want, but **form** or **instance** are very common names. This variable is actually the Webform instance of the following source code.

[**https://github.com/formio/formio.js/blob/master/src/Webform.js**](https://github.com/formio/formio.js/blob/master/src/Webform.js) - For regular webforms

[**https://github.com/formio/formio.js/blob/master/src/Wizard.js**](https://github.com/formio/formio.js/blob/master/src/Wizard.js) - For wizards

[**https://github.com/formio/formio.js/blob/master/src/PDF.js**](https://github.com/formio/formio.js/blob/master/src/PDF.js) - For PDF forms

Because of this, any method within these classes (and their derived classes) can be executed by referencing them on the form or instance variable. So many things can be accomplished using these variables. Here are just a few use cases that be done.

### Log change events

```javascript
// This section of code is the "Form Controller"        
form.on('change', (changed) => {
    console.log('Data was changed!', changed);        
});
```

### Thank You Page after submission

```javascript
// This section of code is the "Form Controller"
form.on('submitDone', function(submission) {
    window.location = '/app/thanks.html';
});
```

### Custom Wizard Controls

```javascript
// This section of code is the "Form Controller"

/**
 * This code assumes a "wizard" is rendered, and that there are buttons in the
 * wizard form that emit the events "gotoNextPage", "gotoPreviousPage" and 
 * "wizardSave"
 **/

form.on('gotoNextPage', function() {
  form.nextPage();
});
form.on('gotoPreviousPage', function() {
  form.prevPage();
});
form.on('wizardSave', function() {
  form.submit().then(function() {
    form.onChange();
    form.nextPage();
  });
});
```

This is such a powerful concept that there is actually a feature called the Form Controller where these controllers can be added to the form JSON and then will be executed in the same fashion as these indicate. This can be configured within the Form Settings of the form and you would use the variable name **instance** instead of form as shown above.

#### Setting the next page in a Wizard

You can manually set the next page to navigate to by using:

```
instance.root.setPage(pageNumber);
```

An example of a button that does this in a Wizard would look like this:

![](/files/cHE0ICo0T32ivH6dj7yl)

## Form Renderer Options

In addition to rendering a form and providing submission data, you can also provide options to the renderer to control its behavior even further. The options are passed as the third parameter to the `Formio.createForm` method as shown below.

```javascript
Formio.createForm(element, src|form, options)
```

The options available are documented as follows.

| Option                             | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Default                                                                                                                                                                                              |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| readOnly                           | Disables all input is set to true                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | false                                                                                                                                                                                                |
| noDefaults                         | Do not establish default submission values. Leave unset unless the user interacts with the form.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | false                                                                                                                                                                                                |
| language                           | The current language for the renderer                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | en                                                                                                                                                                                                   |
| i18n                               | The i18n configurations for the renderer. See [**Form Renderer**](#form-translations-i-18-n) Translations section                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | {}                                                                                                                                                                                                   |
| viewAsHtml                         | Boolean to tell the renderer to render this form in "html" mode.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | false                                                                                                                                                                                                |
| renderMode                         | The mode that the form should render within. This picks different render modes within the templates section. See [**Form Templates**](#form-templates) section for more information.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | form                                                                                                                                                                                                 |
| highlightErrors                    | Highlight the errors for each field.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | true                                                                                                                                                                                                 |
| componentErrorClass                | The default CSS class to be applied to the error dom element.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | formio-error-wrapper                                                                                                                                                                                 |
| template                           | The current template name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |                                                                                                                                                                                                      |
| templates                          | Ability to add custom templates to the renderer. See [**Form Templates**](#form-templates) section.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |                                                                                                                                                                                                      |
| iconset                            | <p>The iconset to use within the renderer. Choices include:<br>bi - Bootstrap Icons<br>fa - Font Awesome</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | bi                                                                                                                                                                                                   |
| buttonSettings                     | <p>For wizards only. Controls the settings and visibility of the wizard button settings. These are configured as follows.</p><p><code>{</code></p><p><code>"buttonSettings": {</code><br><code>"showCancel": true,</code><br><code>"showNext": true,</code></p><p><code>"showPrevious": true</code></p><p><code>"showSubmit": true</code><br><code>}</code></p><p><code>}</code></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | {}                                                                                                                                                                                                   |
| components                         | <p>Allows for overrides for certain components rendered.</p><p>Example: Adds a prefix to all textfield components rendered.</p><p><code>{</code></p><p><code>"components": {</code><br><code>"textfield": {</code><br><code>"prefix": "hello"</code><br><code>}</code><br><code>}</code></p><p><code>}</code></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | {}                                                                                                                                                                                                   |
| disabled                           | <p>Allows for component overrides for disabled fields.</p><p>Example: Disable the firstName component.</p><p><code>{</code></p><p><code>"disabled": {</code><br><code>"firstName": true</code><br><code>}</code></p><p><code>}</code></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | {}                                                                                                                                                                                                   |
| showHiddenFields                   | Boolean that, when set to true, will show all the hidden fields regardless of conditionals.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | false                                                                                                                                                                                                |
| hide                               | <p>Force certain components to be hidden regardless of conditionals.</p><p>Example: Hide the firstName and lastName components.</p><p><code>{</code></p><p><code>"hide": {"firstName": true, "lastName": true}</code></p><p><code>}</code></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |                                                                                                                                                                                                      |
| show                               | <p>Force certain components to be shown regardless of conditionals.</p><p>Example: Show the firstName and lastName components.</p><p><code>{</code></p><p><code>"show": {"firstName": true, "lastName": true}</code></p><p><code>}</code></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |                                                                                                                                                                                                      |
| formio                             | Your own instance of the Formio class.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                                                                                                                                                                                      |
| fileService                        | A custom File Service instance.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |                                                                                                                                                                                                      |
| hooks                              | Allows you to implement certain hooks within the renderer. See [Form Hooks](#hooks).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |                                                                                                                                                                                                      |
| alwaysDirty                        | If set to true, the form will validate on initialization.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | false                                                                                                                                                                                                |
| saveDraft                          | Allows you to implement partial draft submissions. See our [Save As Draft example](https://formio.github.io/formio.js/app/examples/savedraft.html).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |                                                                                                                                                                                                      |
| saveDraftThrottle                  | The Save As Draft feature is invoked at most once per each period defined by this value in milliseconds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | 5000                                                                                                                                                                                                 |
| skipDraftRestore                   | If set to true, the form will not restore a previous draft when rendered.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |                                                                                                                                                                                                      |
| display                            | The type of form to be rendered. Must be 'form' (for a WebForm class), 'wizard' (for a Wizard), or 'pdf' (for a PDF form).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | form                                                                                                                                                                                                 |
| cdnUrl                             | The CDN URL for the renderer's dependency libraries                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | <https://cdn.form.io>                                                                                                                                                                                |
| flatten                            | If set to true, will always render the form as a WebForm. Similar to setting the renderMode option to 'flat'.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |                                                                                                                                                                                                      |
| sanitize                           | If set to false, the renderer will skip sanitization of HTML strings.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |                                                                                                                                                                                                      |
| sanitizeConfig                     | <p>An object that maps to the renderer's HTML sanitization settings. Each object property maps to a <a href="https://github.com/cure53/DOMPurify">DOMPurify</a> configuration option.<br><br>Example:<br><code>{</code><br><code>addAttr: \[/\* an array that maps to DOMPurify's ADD\_ATTR setting </code><em><code>/],</code></em><br><em><code>addTags: \[/</code></em><code> an array that maps to DOMPurify's ADD\_TAGS setting </code><em><code>/],</code></em><br><em><code>allowedTags: \[/</code></em><code> an array that maps to DOMPurify's ALLOWED\_TAGS setting </code><em><code>/],</code></em><br><em><code>allowedAttrs: \[/</code></em><code> an array that maps to DOMPurify's ALLOW\_ATTR setting </code><em><code>/],</code></em><br><em><code>allowedUriRegex: \[/</code></em><code> an array that maps to DOMPurify's ALLOWED\_URI\_REGEXP setting </code><em><code>/],</code></em><br><em><code>addUriSafeAttr: \[/</code></em><code> an array that maps to DOMPurify's ADD\_URI\_SAFE\_ATTR setting \*/]</code><br><code>}</code></p> |                                                                                                                                                                                                      |
| buttonSettings (Wizard Forms)      | The Wizard Form's button settings.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | <p><code>{</code><br><code>showPrevious: true,</code></p><p><code>showNext: true,</code></p><p><code>showSubmit: true,</code></p><p><code>showCancel: !options.readOnly</code><br><code>}</code></p> |
| breadCrumbSettings (Wizard Forms)  | Determines whether or not the Wizard Form's breadcrumb bar is clickable.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | `{ clickable: true }`                                                                                                                                                                                |
| allowPrevious (Wizard Forms)       | Allow the Wizard Form to decrement pages.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |                                                                                                                                                                                                      |
| wizardButtonOrder (Wizard Forms)   | An array of values that determines the order in which the wizard buttons are displayed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `['cancel', 'previous', 'next', 'submit']`                                                                                                                                                           |
| showCheckboxBackground (PDF Forms) | When set to true, ensures that PDF form checkboxes and radio components have a border and a background                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                                                                                                                                                                                      |
| zoom (PDF Forms)                   | <p>The zoom factor of the displayed PDF, relative to 100%.<br>A value of 25 would display the PDF at 125%. A value of -15 would display the PDF at 85%.</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |                                                                                                                                                                                                      |

These options can be applied to the renderer like the following example shows.

Example: Render a submission in read only mode.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/wizard/submission/5a542c9e2a40bf0001e0f8a9', {
  readOnly: true
});
```

## Form Properties

There are many different properties and methods that can be called on the form instance. Many of these methods are documented within the auto-generated SDK documentation found @ <https://formio.github.io/formio.js/docs/>

Within these documentations, you will see some of these methods described as follows.

| Form Class | Documentation                                                               |
| ---------- | --------------------------------------------------------------------------- |
| Webform    | <https://formio.github.io/formio.js/docs/class/src/Webform.js~Webform.html> |
| PDF        | <https://formio.github.io/formio.js/docs/class/src/PDF.js~PDF.html>         |
| Wizard     | <https://formio.github.io/formio.js/docs/class/src/Wizard.js~Wizard.html>   |

While this documentation is helpful to understanding all the methods, here are few of the most used properties on the form instance.

### `form.form`

The current form JSON that is loaded into the form.

### `form.submission`

The current form submission JSON that is loaded into the form.

### `form.schema`

A minified "schema" of the components loaded into the renderer. This is dynamically generated so use sparingly.

### `form.ready`

A promise that is resolved when the form has finished rendered, submission data has been saturated, and the form is "ready".

```javascript
form.ready.then(() => {
    form.submission = {
        data: {
            firstName: 'Joe',
            lastName: 'Smith'
        }
    };
});
```

### `form.loading`

Boolean to indicate if the form is currently loading (true) or not (false).

### `form.src`

The current form source that is loaded within the renderer.

### `form.language`

The current language for this form.

## Form Methods

Here are few of the most used methods on the form instance.

### `form.setForm(form, [flags])`

Sets the JSON schema for the form to be rendered. It returns a promise that resolves when the form has been completely rendered and attached.

| Parameter | Description                                                      |
| --------- | ---------------------------------------------------------------- |
| form      | The JSON schema of the form                                      |
| flags     | Optional flags to control the behavior of the change event loop. |

```javascript
form.setForm({
  components: [
    {
      type: 'textfield',
      key: 'firstName',
      label: 'First Name',
      placeholder: 'Enter your first name.',
      input: true
    },
    {
      type: 'textfield',
      key: 'lastName',
      label: 'Last Name',
      placeholder: 'Enter your last name',
      input: true
    },
    {
      type: 'button',
      action: 'submit',
      label: 'Submit',
      theme: 'primary'
    }
  ]
});
```

### `form.form = {...}`

This is a "setter" alias for `form.setForm.` It can be used as follows.

```javascript
form.form = {
  components: [
    {
      type: 'textfield',
      key: 'firstName',
      label: 'First Name',
      placeholder: 'Enter your first name.',
      input: true
    },
    {
      type: 'textfield',
      key: 'lastName',
      label: 'Last Name',
      placeholder: 'Enter your last name',
      input: true
    },
    {
      type: 'button',
      action: 'submit',
      label: 'Submit',
      theme: 'primary'
    }
  ]
};
```

### `form.setSubmission(submission, [flags])`

Sets a submission and returns the promise when it is ready.

| Parameter  | Description                                            |
| ---------- | ------------------------------------------------------ |
| submission | The submission JSON you wish to set.                   |
| flags      | Flags to control the behavior of the change event loop |

```javascript
form.setSubmission({
  data: {
    firstName: 'Joe',
    lastName: 'Smith',
    email: 'joe@example.com'
  }
});
```

### `form.submission = {...}`

This is a "setter" alias for `form.setSubmission`. It can be used as follows.

```javascript
form.submission = {
  data: {
    firstName: 'Joe',
    lastName: 'Smith',
    email: 'joe@example.com'
  }
};
```

### `form.setSrc(src, [options])`

Set's the "src" of the rendered form. This is the API endpoint for either the Form URL, or the Submission URL. If you provide just a form src, then it will only load the form. If you provide a Submission URL, then it will load both the form and then saturate that form with the submission data.

### `form.src = '...'`

A "setter" alias for `form.setSrc`.

### `form.language = '...'`

Sets the language of the renderer.

### `form.loading = true`

Sets the form to start loading (showing the spinner icon).

### `form.saveDraft()`

Saves a draft submission.

### `form.restoreDraft(userId)`

Restores a draft submission for a specific user ID

### `form.redraw()`

Force a redraw of the form.

### `form.resetValue()`

Force a reset value on the form.

### `form.submit()`

Submit the form.

### `form.checkData()`

Performs a check on the submission data for calculations, conditionals, and validations.

### `form.everyComponent(fn)`

Iterate through every component within the form.

| Parameter | Description                                                                                                                                                                                                                                                                                                                                                                                                              |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| fn        | <p>A callback that will be called for every component. The signature for this component is as follows.</p><p><code>fn(component, components, index)</code></p><ul><li>component - The component instance for the current component.</li><li>components - An array of the components that are the "siblings" of the component</li><li>index - The index of the component within the components being triggered.</li></ul> |

```javascript
form.everyComponent((component) => {
  if (component.component.key === 'firstName') {
    component.setValue('Joe');
  }
});
```

### `form.getComponent(path|key, [fn])`

Retrieve a component from the form.

| Parameter | Description                                                                     |
| --------- | ------------------------------------------------------------------------------- |
| path\|key | The key of the component you wish to fetch, or the data path of that component. |
| fn        | Callback function to be called when the component is found.                     |

```javascript
const email = form.getComponent('email');
email.setValue('joe@examle.com');
```

### `form.checkValidity([data], [dirty], [row], [silent])`

Checks the form validity and updates the errors if the validity fails.

| Parameter | Description                                                                                                                                                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data      | The data to check against. If no data is provided, then the submission data in context will be used.                                                          |
| dirty     | If this should force the "dirty" flag on the components when performing the checks. If "true" this will highlight all invalid form fields as red on the form. |
| row       | The row data to check against. If no data is provided, then the contextual row data will be used.                                                             |
| silent    | If "true", then this will perform a passive check for validity and will not affect the visuals of the form and highlight any fields red if they are invalid.  |

```javascript
if (!form.checkValidity(null, false, null, true)) {
  alert('The form is invalid!);
}
```

## Form Events

Within the Form.io renderer, there are a number of events that are fired that allow you to respond to these events and then do something once they fire. A very common example of this is to listen for anytime someone changes a field within the form, log that change for audit reasons.

The Form.io renderer uses the [EventEmitter3](https://github.com/primus/eventemitter3) library to manage all of the event handling that occurs within the renderer, and because of this, any method that this library includes can also be used within the renderer, as the following example illustrates.

```javascript
// Listen for change events and log the changes as they occur.
form.on('change', (changed) => {
    console.log(changed);
});
```

The following events are triggered within the Form.io renderer.

| Event              | Description                                                                                                                          | Arguments                                                                                                                                                                                                                                                                                               |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| change             | A value has been changed within the rendered form                                                                                    | <ul><li>changed: The changes that occurred, and the component that triggered the change. See "componentChange" event for description of this argument</li><li>flags: The change loop flags.</li><li>modified: Flag to determine if the change was made by a human interaction, or programatic</li></ul> |
| error              | An event that fires when errors have occurred within the renderer                                                                    | <ul><li>errors: An array of errors that occurred.</li></ul>                                                                                                                                                                                                                                             |
| formLoad           | The form json has finished loading                                                                                                   | <ul><li>form: The form json that was loaded</li></ul>                                                                                                                                                                                                                                                   |
| submit             | A form has been submitted                                                                                                            | <ul><li>submission: The submission json object.</li><li>saved: Boolean to indicate if the submission was saved via API or not.</li></ul>                                                                                                                                                                |
| submitDone         | Similar to "submit" but only fires when the submission is "saved" via API                                                            | <ul><li>submission: The submission json object.</li></ul>                                                                                                                                                                                                                                               |
| submitError        | Called when a submission error has occurred                                                                                          | <ul><li>error: The error that was fired.</li></ul>                                                                                                                                                                                                                                                      |
| render             | The form is done rendering and has completed the attach phase.                                                                       | <ul><li>element: The root element of the renderer</li></ul>                                                                                                                                                                                                                                             |
| initialized        | Called when the form has completed the render, attach, and one initialization change event loop                                      |                                                                                                                                                                                                                                                                                                         |
| requestDone        | Called when the Action url is provided to the renderer to submit to a custom action url. This is fired when the request is finished. |                                                                                                                                                                                                                                                                                                         |
| languageChanged    | Called when the language has been changed.                                                                                           |                                                                                                                                                                                                                                                                                                         |
| saveDraftBegin     | Called when a save draft has started                                                                                                 |                                                                                                                                                                                                                                                                                                         |
| saveDraft          | Called when a save draft operation has finished                                                                                      | <ul><li>submission: The submission that was saved as draft.</li></ul>                                                                                                                                                                                                                                   |
| saveDraftError     | Called when an error occurred while saving a draft.                                                                                  | <ul><li>error: The error that was fired.</li></ul>                                                                                                                                                                                                                                                      |
| restoreDraft       | Called when a draft submission has been restored into the renderer.                                                                  | <ul><li>draft: The draft submission that was restored.</li></ul>                                                                                                                                                                                                                                        |
| restoreDraftError  | Called when an error occurred while restoring a draft.                                                                               | <ul><li>error: The error that was fired.</li></ul>                                                                                                                                                                                                                                                      |
| submissionDeleted  | Called when a submission has been deleted.                                                                                           | <ul><li>submission: The submission that was deleted.</li></ul>                                                                                                                                                                                                                                          |
| redraw             | Triggered when a component redraws                                                                                                   |                                                                                                                                                                                                                                                                                                         |
| focus              | Triggered when an input component has received focus                                                                                 | <ul><li>instance: The component instance</li></ul>                                                                                                                                                                                                                                                      |
| blur               | Triggered when an input component has been blurred                                                                                   | <ul><li>instance: The component instance.</li></ul>                                                                                                                                                                                                                                                     |
| componentChange    | Triggered when a specific component changes                                                                                          | <p>An object containing the following properties.</p><ul><li>instance: The component instance</li><li>component: The component json</li><li>value: The value that was changed</li><li>flags: The flags for the change event loop.</li></ul>                                                             |
| componentError     | Triggered when an error occurs within a specific component                                                                           | <ul><li>error: The error that has occurred.</li></ul>                                                                                                                                                                                                                                                   |
| submitButton       | Triggered for button components configured as a Submit action, when they are clicked.                                                |                                                                                                                                                                                                                                                                                                         |
| customEvent        | Triggered for button components configured as Event action. This is fired when they are clicked.                                     | <p>An object containing the following properties.</p><ul><li>type: The configured event type.</li><li>component: The component json</li><li>data: The contextual data for this button.</li><li>event: The click event</li></ul>                                                                         |
| editGridAddRow     | For EditGrid components, fired when a row has been added                                                                             | <p>An object containing the following properties.</p><ul><li>component: The component json.</li><li>row: The edit grid contextual row object.</li></ul>                                                                                                                                                 |
| editGridEditRow    | For EditGrid components, fired when a row has been opened for editing                                                                | <p>An object containing the following properties.</p><ul><li>component: The component json.</li><li>row: The edit grid contextual row object.</li><li>instance: The edit grid instance object.</li></ul>                                                                                                |
| editGridOpenModal  | For EditGrid components, fired when a row has been opened as a modal. Available when the EditGrid has 'Display as Modal' enabled.    | <p>An object containing the following properties.</p><ul><li>component: The component json.</li><li>row: The edit grid contextual row object.</li><li>instance: The edit grid instance object.</li></ul>                                                                                                |
| editGridSaveRow    | For EditGrid components, fired when a row has been saved.                                                                            | <p>An object containing the following properties.</p><ul><li>component: The component json</li><li>row: The edit grid contextual row object.</li></ul>                                                                                                                                                  |
| editGridDeleteRow  | For EditGrid components, fired when a row has been deleted.                                                                          | <p>An object containing the following properties.</p><ul><li>index: The index of the row that was deleted.</li></ul>                                                                                                                                                                                    |
| fileUploadingStart | For File components, fired when a file upload has started                                                                            |                                                                                                                                                                                                                                                                                                         |
| fileUploadingEnd   | For File components, fired when the file upload had completed.                                                                       |                                                                                                                                                                                                                                                                                                         |
| rowAdd             | For DataTable components, fired when the “+” button was clicked, before entering data.                                               | <ul><li>instance: The DataTable instance.</li></ul>                                                                                                                                                                                                                                                     |
| rowAdded           | For DataTable components, fired after saving a new row                                                                               | <ul><li>rowData: object with row data</li><li>instance: The DataTable instance.</li></ul>                                                                                                                                                                                                               |
| rowEdit            | For DataTable components, fired when the “Edit Row” button was clicked, before editing data.                                         | <ul><li>rowData: object with row data</li><li>rowIndex</li><li>index</li><li>instance: The DataTable instance</li></ul>                                                                                                                                                                                 |
| rowEdited          | For DataTable components, fired after editing row                                                                                    | <ul><li>rowData: object with row data</li><li>rowIndex</li><li>instance: The DataTable instance.</li></ul>                                                                                                                                                                                              |
| rowDelete          | For DataTable components, fired when a row was deleted                                                                               | <ul><li>rowData: object with row data</li><li>rowIndex</li><li>index</li><li>instance: The DataTable instance</li></ul>                                                                                                                                                                                 |
| rowClick           | For DataTable components, fired when the row was clicked                                                                             | <ul><li>rowData: object with row data</li><li>rowIndex</li><li>index</li><li>instance: The DataTable instance</li></ul>                                                                                                                                                                                 |
| nextPage           | For Wizards, this is triggered when the next page is navigated to.                                                                   | <p>An object that contains the following properties.</p><ul><li>page: The current page</li><li>submission: The current submission.</li></ul>                                                                                                                                                            |
| prevPage           | For Wizard, this is triggered when the previous page is navigated to.                                                                | <p>An object that contains the following properties.</p><ul><li>page: The current page</li><li>submission: The current submission</li></ul>                                                                                                                                                             |
| pagesChanged       | For Wizard, this is triggered when the pages of the wizard changes.                                                                  |                                                                                                                                                                                                                                                                                                         |
| wizardPageSelected | For Wizard, this is triggered when the wizard page has been selected and is done rendering.                                          | <ul><li>page: The page that was selected</li><li>index: The index of the page that was selected.</li></ul>                                                                                                                                                                                              |

## Hooks

Hooks allow you to alter the behavior of the form and block the execution of certain functionalities in favor of providing your own logic. A good example of this is to provide a `beforeSubmit` hook where you can block the submission and alter the the submission or even perform your own validations. Each hook is provided using the options of the renderer like so.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    beforeSubmit: (submission, next) => {
      // Alter the submission
      submission.data.email = 'me@example.com';
      
      // Only call next when we are ready.
      next();
    }
  }
})
```

Here is a list of all available hooks within the renderer.

### `beforeSubmit(submission, next)`

Allows you to hook into the submit handler before the submission is being made to the server. Each parameter is described as follows.

| Param      | Description                                                                                                                                                                                                                                                                                                                                                            |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| submission | The submission data object that is going to be submitted to the server. This allows you to alter the submission data object in real time.                                                                                                                                                                                                                              |
| next       | Called when the `beforeSubmit` handler is done executing. If you call this method without any arguments, like `next()`, then this means that no errors should be added to the default form validation. If you wish to introduce your own custom errors, then you can call this method with either a single error object, or an array of errors like the example below. |

#### Custom Errors

It is a very common use case to provide your own custom errors to the submit handler. To achieve this, you can call the `next` callback with either a single error object, or an array of errors you wish to introduce to the error handler. Here is an example of how to introduce some custom errors.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    beforeSubmit: (submission, next) => {
      // Make a custom ajax call.
      $.ajax({
        url: 'https://myserver.com/validate',
        method: 'POST',
        data: submission,
        complete: (errors) => {
          let submitErrors = null;
          if (errors) {
            submitErrors = [];
            errors.forEach((error) => {
              submitErrors.push({
                message: error.toString()
              });
            });
          }
          next(submitErrors);
        }
      });
    }
  }
})
```

#### Saving and Restoring submissions

This hook can also be used to ensure the integrity of submission data so that if any error occurs, the submission can be restored. The following code illustrates how this can be done.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    beforeSubmit: (submission, next) => {
      localStorage.setItem('currentData', JSON.stringify(submission.data);
      next();
    }
  }
}).then(function(form) {
  var currentData = localStorage.getItem('currentData');
  if (currentData) {
    form.submission = {data: JSON.parse(currentData)};
  }

  form.on('submitDone', function() {
    localStorage.removeItem('currentData');
  });
});
```

### `beforeNext(currentPage, submission, next)`

Allows you to hook into the submit handler before the switching to next page. Each parameter is described as follows.

| Param       | Description                                                                                                                                                                                                                                                                                                                                                          |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| currentPage | The current page data object. This allows you to use page data for your submissions on each page.                                                                                                                                                                                                                                                                    |
| submission  | The submission data object that is going to be submitted to the server. This allows you to alter the submission data object in real time.                                                                                                                                                                                                                            |
| next        | Called when the `beforeNext` handler is done executing. If you call this method without any arguments, like `next()`, then this means that no errors should be added to the default form validation. If you wish to introduce your own custom errors, then you can call this method with either a single error object, or an array of errors like the example below. |

#### **Custom Errors**

It is a very common use case to provide your own custom errors to the submit handler before user switching to next page. To achieve this, you can call the `next` callback with either a single error object, or an array of errors you wish to introduce to the error handler. Here is an example of how to introduce some custom errors.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    beforeNext: (currentPage, submission, next) => {
      // Make a custom ajax call.
      $.ajax({
        url: 'https://myserver.com/validate',
        method: 'POST',
        data: submission,
        complete: (errors) => {
          let submitErrors = null;
          if (errors) {
            submitErrors = errors.map(error => ({
              message: error.toString()
            }));
          }
          next(submitErrors);
        }
      });
    }
  }
})
```

### `beforePrev(currentPage, submission, next)`

Called before the previous page has been navigated.

| Param       | Description                                                                                                                                                                                                                                                                                                                                                          |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| currentPage | The current page data object. This allows you to use page data for your submissions on each page.                                                                                                                                                                                                                                                                    |
| submission  | The submission data object that is going to be submitted to the server. This allows you to alter the submission data object in real time.                                                                                                                                                                                                                            |
| next        | Called when the `beforePrev` handler is done executing. If you call this method without any arguments, like `next()`, then this means that no errors should be added to the default form validation. If you wish to introduce your own custom errors, then you can call this method with either a single error object, or an array of errors like the example below. |

### `customValidation(submission, next)`

Provides a hook to inject custom validations into the submission process.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    customValidation: (submission, next) => {
      // Make a custom ajax call.
      $.ajax({
        url: 'https://myserver.com/validate',
        method: 'POST',
        data: submission,
        complete: (errors) => {
          let submitErrors = null;
          if (errors) {
            submitErrors = errors.map(error => ({
              message: error.toString()
            }));
          }
          next(submitErrors);
        }
      });
    }
  }
})
```

| Param      | Description                                                                                                                                                                                                                                                                                                                                                            |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| submission | The submission data object that is going to be submitted to the server. This allows you to alter the submission data object in real time.                                                                                                                                                                                                                              |
| next       | Called when the `beforeSubmit` handler is done executing. If you call this method without any arguments, like `next()`, then this means that no errors should be added to the default form validation. If you wish to introduce your own custom errors, then you can call this method with either a single error object, or an array of errors like the example below. |

### `attachWebform(element, instance)`

Called once the webform has started its attach phase.

| Parameter | Description                                       |
| --------- | ------------------------------------------------- |
| element   | The DOM element that the webform is attaching to. |
| instance  | The webform instance object.                      |

The method should either return the "element" or another DOM element that will be used to attach the webform object to.

### `beforeCancel()`

Called before a form is canceled which provides the ability to abort the cancel process.

Example: If you wish to reject a form cancel process.

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    beforeCancel: () => {
      // Return false to abort the cancel process.
      return false;
    }
  }
})
```

### `component()`

Triggered when a component has been instantiated. The "this" pointer will point to the current component instance.

### `attachComponent(element, instance)`

Triggered when a component has been attached to an element.

| Parameter | Description                                         |
| --------- | --------------------------------------------------- |
| element   | The DOM element that the component is attaching to. |
| instance  | The component instance object.                      |

Returns the "element" or another element this component should be attached to.

### `setDataValue(value, key, data)`

Hook into the setting of a data value for a specific component.

| Parameter | Description                            |
| --------- | -------------------------------------- |
| value     | The value that is being set.           |
| key       | The component key                      |
| data      | The components contextual data object. |

Returns the new value that should be made to that component.

### `addComponents(components, instance)`

Called before a NestedComponent instantiates and adds its components provided by the JSON of those components.

| Parameter  | Description                                            |
| ---------- | ------------------------------------------------------ |
| components | An array of the components JSON that is getting added. |
| instance   | The nested component instance.                         |

Returns the new array of components that should be added.

### `addComponent(component, data, before)`

Called just before a component is going to be instantiated.

| Parameter | Description                                      |
| --------- | ------------------------------------------------ |
| component | The component JSON that is going to be added.    |
| data      | The component data context for this component    |
| before    | The DOM element to insert the component 'before' |

Returns the new component JSON that should be used when adding a component to the renderer.

**Example: Change all rendered fields to be required.**

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  hooks: {
    addComponent: (component) => {
      component.required = true;
      return component;
    }
  }
})
```

### `attachComponents(element, components, container, instance)`

Called just before a nested component attaches its children to their elements.

| Parameter  | Description                                |
| ---------- | ------------------------------------------ |
| element    | The DOM element that contains the children |
| components | An array of component instances.           |
| container  | The JSON array of components               |
| instance   | The nested component instance.             |

### `onCalendarOpen()`

Triggered when the calendar widget has been opened.

### `onCalendarClose()`

Triggered when the calendar widget closes.

## Overriding Behavior

In many cases, you will need to override certain behaviors of the renderer that neither a configuration, hook, or form event will be able to achieve the behavior you are looking for. When this occurs, you can override any behavior of the form renderer and form builder by hooking into specific methods and defining your own behavior or routines. Any overrides to the Form.io renderer can be achieved through the `Formio` global object. This object can be seen if you inspect the console within the [Form.io Portal](https://portal.form.io) by just typing `Formio.` into the console and will then autocorrect the following variables available to you.

![The Formio class interface](/files/-MblvS4vYF6Lmyg3Ts4C)

Each one of these objects allow access to the underlying classes that define the behavior of the renderer. They are described as follows.

| Interface           | Description                                                                |
| ------------------- | -------------------------------------------------------------------------- |
| `Formio.Builders`   | Interface to the form builder classes                                      |
| `Formio.Components` | Interface to the form component classes.                                   |
| `Formio.Displays`   | Interface to the form renderer classes (form, wizard, pdf)                 |
| `Formio.Providers`  | Interface into the form provider classes (file uploads, address providers) |
| `Formio.Rules`      | Interface into the form validation rules.                                  |
| `Formio.Templates`  | Interface to the form template.                                            |

Each one of these introduces a list of classes that can be overridden such as the following. A great example of this are the different components that can be instantiated within a form, which can be seen by typing `Formio.Components.components` into the console.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

Each of these are a separate class that will instantiate when the component is created. This is very useful because we can access the prototype of each of these classes to override certain behavior. The methods that can be overridden can be found by first navigating to the source code of that specific component and viewing the methods available to that class as well as any class that it derives from.

For example, let's suppose that you wish to override the behavior of the Button component to trigger a browser "alert" asking the user if they wish to submit the form before it is submitted. We can achieve this by first viewing the source code behind the Button component found at <https://github.com/formio/formio.js/blob/master/src/components/button/Button.js>

Within this code, we will see that there is a method called `onClick` that is executed when the button is clicked. We can inject our alert by first saving this function to a variable, then override the method with our own implementation that will call the original onClick when the user accepts the `window.confirm`.

```javascript
var onClick = Formio.Components.components.button.prototype.onClick;
Formio.Components.components.button.prototype.onClick = function(event) {
  if (window.confirm('Are you sure you want to press this button?')) {
    onClick.call(this, event);
  }
};
```

We can actually test this within the Form.io portal by copying and pasting the following within the Developer console when you are on the Form.io portal as the following illustrates.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

Now, we just need to render the form using the "Use" tab (which will execute our override when it renders the button component), and then try to submit the form to get the following.

![](/files/-MblvS4vYF6Lmyg3Ts4C)

This code can now be copied into your application where any form rendered within your application will execute the your override. An example of what this method override would look like in your application would be as follows.

```javascript
import { Formio } from '@formio/js';
const onClick = Formio.Components.components.button.prototype.onClick;
Formio.Components.components.button.prototype.onClick = function(event) {
  if (window.confirm('Are you sure you want to press this button?')) {
    onClick.call(this, event);
  }
};
```

Using this method, it is now possible to override any aspect of the renderer or builder to achieve the kind of custom behavior that you are looking for. The best thing to do is to investigate the source code found @ <https://github.com/formio/formio.js> to see all the different kinds of methods that can be overridden to create the behaviors you are looking for.

### Overriding GET and SET methods

In some situations, you may also need to override a "getter" or a "setter" method. These methods look like the following within the base classes.

```javascript
export default class HTMLComponent extends Component {
    ...
    
    get content() {
        return ...;
    }
    
    ...
}
```

These methods can be overridden in a similar way described above, but they do require some different syntax. In order to achieve this, we need to use the `Object.getOwnPropertyDescriptor` and `Object.defineProperty` methods. For example, if we wish to append some HTML code to every HTMLComponent using the content method, you could write the following logic which will override the content getter method.

```javascript
const contentProps = Object.getOwnPropertyDescriptor(Formio.Components.components.html.prototype, 'content');
const contentGet = contentProps.get;
contentProps.get = function() {
  return contentGet.call(this) + '<span>Additional Content!</span>';
}
Object.defineProperty(Formio.Components.components.html.prototype, 'content', contentProps);
```

### Overriding Base Classes

In some cases, you may also need to override the base classes which are used by all components. To do this correctly is tricky since it does require that you override the base class methods BEFORE the other component classes are declared. This can be done by adding some logic that is imported into your application BEFORE the renderer is imported like so.

```javascript
// Import just the base component.
import Component from '@formio/js/components/_classes/component/Component';
const baseInit = Component.prototype.init;
Component.prototype.init = function() {
    // Do something custom here!!
    return baseInit.call(this);
}

// Now import formiojs so all components will use the overridden base component.
import { Formio } from '@formio/js';
```

This will now allow you to alter the behaviors of all components that are instantiated within the form.io renderer.


# Form Embedding

How to embed a Form.io form within your application.

The Form.io platform is an advanced JavaScript platform that enables Developers and Non-Developers alike to build forms and easily embed them within their own applications and websites. There are multiple ways that we offer the embedding of our forms, ranging from the non-technical, yet powerful, **Quick Inline Embedding,** to the more advanced JavaScript embedding. All of the Form.io components are embeddable, and this documentation will outline all the ways you can embed a form.

## Quick Inline Embedding

By far the easiest way to embed a form within your application is to use the Quick Inline Embedding mechanism. This provides a one-line code snippet that is capable of embedding a form directly inline within a browser page. To embed a form, you simply copy and paste the following code directly in the place on your HTML website you would like to see the form.

<figure><img src="/files/1AEKG9n19opCosPlWTEd" alt=""><figcaption></figcaption></figure>

```html
<script src="https://cdn.form.io/js/formio.embed.js?src=https://forms.mysite.com/myproject/&libs=true"></script>
```

{% hint style="info" %}
Navigate to the following link for more information on [**Form.io CDNs**](https://help.form.io/dev/form-development/spaces/dE1To8ypyE1yhXEJ7QlD/pages/2ae5hrS2IA25reIexyXB#what-are-the-form.io-cdns)
{% endhint %}

You can change the form you embed by simply changing the `https://forms.mysite.com/myproject/myform` string to the URL of your Form. This can be found by navigating to your form, and then clicking on the "link" symbol next to the form name as shown below.

![](/files/ZmGeZ9rEq5NwxYW8VSZS)

If you wish to have an easy interface to configure this Embed, then please check out our online [**Quick Inline Embed Configurator**](https://pro.formview.io/#/examples/embed?header=1\&reset=1).

You can also click on the **Embed** tab within every form so see an interface that allows you to easily configure this embed code so that you can copy and paste this into your application. There are a number of advanced options that you can use to configure how the embedded form behaves by adding Query parameters on the "src" URL of the script tag. For example, if you wish to load all the dependent CSS libraries along with the embed code, you can add the following to the end of the embed src like so.

```
...?src=https://forms.mysite.com/myproject/&libs=true"></script>
```

Here is a list of all available options you can pass into this embed script along with more advanced functionality.

### Quick Inline Embed Query Params

The following is a list of query parameters that can be provided to the Quick Inline Embed src string as shown in the example above.

| Parameter | Description                                                                                                                                                                                                                                                                                                                                             | Default                                                    |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| src       | (Required) The form url you wish to embed. If you use the **form** parameter, then this parameter is not required.                                                                                                                                                                                                                                      |                                                            |
| libs      | Used to load all dependent CSS libraries to render the form. This also renders the form within a ShadowDOM which isolates the CSS and rendering of the form so that no outside styles will collide with the form. This is ideal if you wish to embed a form within a CMS such as Wordpress or Drupal. Set to "true" if you wish to enable this feature. | false                                                      |
| template  | <p>This determines the CSS template to use when rendering the form. The available templates are as follows.</p><p>- \[empty]: Render the form in the default Bootstrap 4 template</p><p>- uswds: Render the form in USWDS template</p><p>- semantic: Render the form in the Semantic template.</p>                                                      |                                                            |
| class     | The default "wrapper" class to include on the outside element of the rendered form.                                                                                                                                                                                                                                                                     | formio-form-wrapper                                        |
| project   | The Project this form is associated with. This is needed along with the "base" parameter if you are planning on uploading files. This is because the renderer needs to determine the correct project url to upload the file against. Example: "<https://examples.form.io>" for our Hosted platform.                                                     |                                                            |
| base      | The API base for this Form.io platform behind the form. For example: "<https://api.mysite.com>" is the value for our Hosted platform.                                                                                                                                                                                                                   |                                                            |
| submit    | The endpoint you would like to POST the submission toward. This allows you to send the submission to other forms, or other endpoints other than the default "form" submission endpoint.                                                                                                                                                                 |                                                            |
| debug     | Enable debug mode. Adds a number of console.log records to the browser on how this form is progressing through the embedding code.                                                                                                                                                                                                                      | false                                                      |
| redirect  | The URL you would like to redirect to after they have finished submitting the form. For example, you could provide a "thank you" page URL as the value of this parameter.                                                                                                                                                                               |                                                            |
| return    | Alias of "redirect"                                                                                                                                                                                                                                                                                                                                     |                                                            |
| script    | This allows you to change the location of the formiojs renderer script.                                                                                                                                                                                                                                                                                 | [**This url**](https://cdn.form.io/js/formio.form.min.js)  |
| style     | This allows you to change the location of the formiojs renderer style                                                                                                                                                                                                                                                                                   | [**This url**](https://cdn.form.io/js/formio.form.min.css) |

### Advanced Usage

In addition to being able to control the Quick Inline Embed through the use of parameters, you can also control the embedding through a use of a configuration that is added before the inline embed code. This code uses the global **FormioConfig** to tell the embedding script how you would like to inject within the form rendering process. The following shows an example of adding an after render handler to trigger once the form has finished rendering.

```markup
<script type="text/javascript">
window.FormioConfig = {
  after: function(instance) {
    instance.on('change', function(changed) {
      // This is triggered every time something on the form changes.
      console.log(changed);
    });
  }
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js?src=https://forms.mysite.com/myproject/myform"></script>
```

The following parameters can be used within the **FormioConfig** variable to control the embedded flow.

#### `FormioConfig.before`

This is a callback that is executed before the Form is rendered. This provides a good opportunity to make modifications to the `Formio` renderer class as well as the configurations that are going to be passed to the renderer before the rendering occurs.

**Example 1**: **Extend a method for a component.**

This next example shows how a method within a component can be extended or overridden to provide custom functionality.

```markup
<script type="text/javascript">
window.FormioConfig = {
  before: function(Formio, element, config) 
    // Override the checkbox setValue method like so.
    var setValue = Formio.Components.components.checkbox.prototype.setValue;
    Formio.Components.components.checkbox.prototype.setValue = function(value) {
      console.log('The checkbox value has been set!');
      return setValue.call(this, value);
    };
    
    // This is the wrapper element for the renderer.
    console.log(element);
    
    // Override a configuration. Like forcing a language setting.
    config.config.language = 'sp';
  }
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js?src=https://forms.mysite.com/myproject/myform"></script>
```

#### Example 2: Modifying a template

This next example uses the template system to modify the "input" template to provide a wrapper around all inputs rendered by the renderer. All templates can be found by going to <https://github.com/formio/formio.js/tree/master/src/templates/bootstrap>. This example shows how we can add a wrapper around all of the inputs within the renderer.

```markup
<script type="text/javascript">
window.FormioConfig = {
  before: function(Formio, element, config) {
    var inputForm = Formio.Templates.current.input.form;
    Formio.Templates.current = {
      input: {
        form: (ctx) => {
          return '<div class="input-wrapper">' + inputForm(ctx) + '</div>';
        }
      }
    };
  } 
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js?src=https://forms.mysite.com/myproject/&libs=true"></script>
```

#### `FormioConfig.after`

This is a callback that is called after the form is done rendering. This is useful if you wish to register for certain form events and then perform actions based on those events, like so.

**Example:**

```markup
<script type="text/javascript">
window.FormioConfig = {
  after: function(instance) {
    instance.on('change', function(changed) {
      // This is triggered every time something on the form changes.
      console.log(changed);
    });
  }
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js?src=https://forms.mysite.com/myproject/myform"></script>
```

#### `FormioConfig.config`

This allows you to alter the Renderer configuration that is passed into the `Formio.createForm` method. This is useful if you wish to provide a number of translations into the renderer like so.

**Example:**

```markup
<script type="text/javascript">
window.FormioConfig = {
  config: {
    language: 'sp',
    i18n: {
      sp: {
        'First Name': 'Nombre de pila',
        'Last Name': 'Apellido'
      },
      ch: {
        'First Name': '名字',
        'Last Name': '姓'
      }
    }
  }
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js?src=https://forms.mysite.com/myproject/myform"></script>
```

#### `FormioConfig.form` **and `FormioConfig.submission`**

The `form` and `submission` configuration allows you to provide the form or submission in JSON format to the renderer. If the `form` is provided, then the **src** is no longer required and renders the form in JSON format. If the `submission` is provided, then it is used to automatically populate the form with that submission data.

**Example:**

```markup
<script type="text/javascript">
window.FormioConfig = {
  config: {
    readOnly: true
  },
  form: {
    components: [
      {
        type: 'textfield',
        key: 'firstName',
        label: 'First Name'
      }
    ]
  },
  submission: {
    data: {
      firstName: 'Travis'
    }
  }
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js"></script>
```

#### `FormioConfig.libs`

This configuration allows you to configure the URL for all the libs that are loaded within the renderer using the **libs** query parameter. The libs are defined and can be overridden, as follows.

```markup
<script type="text/javascript">
window.FormioConfig = {
  libs: {
    uswds: {
      js: 'https://cdn.jsdelivr.net/npm/uswds@2.10.0/dist/js/uswds.min.js',
      css: 'https://cdn.jsdelivr.net/npm/uswds@2.10.0/dist/css/uswds.min.css'
    },
    fontawesome: {
      css: 'https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css'
    },
    bootstrap: {
      css: 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css'
    }
  }
};
</script>
<script src="https://cdn.form.io/js/formio.embed.js"></script>
```

## IFrame Embedding (fallback)

The Form.io [**Form Viewer** ](https://github.com/formio/formio-viewer)can be used to embed forms using iframes. It contains a special library called [**Seamless**](https://github.com/travist/seamless) which will auto resize the iframe to the size of the form within the Parent page (the one doing the embedding). You can change the form to embed mode using the `iframe=1` parameter on the URL, which is what is used within the {{ site.formio }} embed code as follows.

```markup
<script type="text/javascript">(function a(d, w, u) {var h = d.getElementsByTagName("head")[0];var s = d.createElement("script");s.type = "text/javascript";s.src = "https://portal.form.io/lib/seamless/seamless.parent.min.js";s.onload = function b() {var f = d.getElementById("formio-form-57aa1d2a5b7a477b002717fe");if (!f || (typeof w.seamless === u)) {return setTimeout(b, 100);}w.seamless(f, {fallback:false}).receive(function(d, e) {});};h.appendChild(s);})(document, window);</script>
<iframe id="formio-form-57aa1d2a5b7a477b002717fe" style="width:100%;border:none;" height="600px" src="https://formview.io/#/examples/example?iframe=1&header=0"></iframe>
```

## JavaScript Embedding

JavaScript Embedding is covered in great detail in the [**Form Renderer**](/dev/form-development/form-renderer) section of our help documentation.

## Form Builder Embedding

Form Builder embedding is covered in great detail in the [**Form Builder**](/dev/form-development/form-builder) section of our help documentation.

## Framework Embedding

Form.io also supports embedding a form in many UI frameworks such as Angular, React, and Vue. These are discussed in great detail in the [**Frameworks**](/dev/javascript-development/frameworks) section.

####


# Translations

Documentation of Form.io Translations

## Introduction

The Form.io Platform uses the [**i18Next**](https://www.i18next.com/) system as the mechanism for displaying all of the translations within the JavaScript Renderer and Builder. Refer to the i18Next documentation to understand all of the mechanisms that are available to handle translations within an application and forms rendered by Form.io. The Form.io Renderer exposes the i18next platform within the`i18next` variable in the renderer, and all options for this library can be introduced through the `i18n` configuration variable.

The following example illustrates how the i18next framework can be initialized and accessed within the Form.io renderer:

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
    i18n: {...} // These options are passed to the i18Next framework
}).then((form) => {
    console.log(form.i18next); // Exposes the i18Next framework instance.
    
    form.language = 'es'; // Changes the language of the i18Next framework.
});
```

Following initialization, the features documented for the[ **i18Next framework**](https://www.i18next.com/) apply.\
\
The following topics provide additional guidance on rendering a form with internationalization:

## Rendering Translations

In order to provide translations to the renderer, introduce these translations using i18n configurations. There are also a few methods within the Form.io Renderer that can be used to change the language dynamically. For example, the following HTML code introduces buttons within the application that will trigger a language change:

```markup
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
<script src="https://cdn.form.io/js/formio.embed.js"></script>

<div class="btn-group">
  <button type="button" class="btn btn-primary" onclick="setLanguage('es')">Español</button>
  <button type="button" class="btn btn-secondary" onclick="setLanguage('en')">English</button>
  <button type="button" class="btn btn-info" onclick="setLanguage('zh')">中文</button>
  <button type="button" class="btn btn-success" onclick="setLanguage('ar')">العربية</button>
</div>

<div id="formio"></div>
```

After this, provide the following code to define the form, provide the translated text, and then dynamically change the text when the buttons have been clicked. The code will look as follows:

```javascript
Formio.createForm(document.getElementById('formio'), {
    components: [
      {
        type: 'textfield',
        key: 'firstName',
        label: 'First Name',
        tooltip: "Name",
        placeholder: 'Enter your first name',
        input: true
      },
      {
        type: 'textfield',
        key: 'lastName',
        label: 'Last Name',
        placeholder: 'Enter your last name',
        input: true
      },
      {
        label: 'When did you start using the Form.io platform?',
        tableView: false,
        datePicker: {
          disableWeekends: false,
          disableWeekdays: false,
        },
        enableMinDateInput: false,
        enableMaxDateInput: false,
        validateWhenHidden: false,
        placeholder: 'Enter the date',
        key: 'startDate',
        type: 'datetime',
        input: true,
        widget: {
          type: 'calendar',
          displayInTimezone: 'viewer',
          locale: 'en',
          useLocaleSettings: false,
          allowInput: true,
          mode: 'single',
          enableTime: true,
          noCalendar: false,
          format: 'yyyy-MM-dd hh:mm a',
          hourIncrement: 1,
          minuteIncrement: 1,
          time_24hr: false,
          minDate: null,
          disableWeekends: false,
          disableWeekdays: false,
          maxDate: null,
        }
      },
      {
        type: 'survey',
        key: 'questions',
        label: 'Survey',
        values: [
          { label: 'Great', value: 'great' },
          { label: 'Good', value: 'good' },
          { label: 'Poor', value: 'poor' }
        ],
        questions: [
          { label: 'How would you rate the Form.io platform?', value: 'howWouldYouRateTheFormIoPlatform' },
          { label: 'How was Customer Support?', value: 'howWasCustomerSupport' },
          { label: 'Overall Experience?', value: 'overallExperience' }
        ]
      },
      {
        type: 'button',
        action: 'submit',
        label: 'Submit',
        theme: 'primary'
      }
    ]
  }, {
    language: 'en',
    i18n: {
      es: {
        'First Name': 'Nombre de pila',
        'Name': 'Nombre',
        'Last Name': 'Apellido',
        'Enter your first name': 'Ponga su primer nombre',
        'Enter your last name': 'Introduce tu apellido',
        'When did you start using the Form.io platform?': '¿Cuándo empezaste a utilizar la plataforma Form.io?',
        'Enter the date': 'Introduce la fecha',
        'How would you rate the Form.io platform?': '¿Cómo calificaría la plataforma Form.io?',
        'How was Customer Support?': '¿Cómo fue el servicio de atención al cliente?',
        'Overall Experience?': '¿Experiencia general?',
        Survey: 'Encuesta',
        Excellent: 'Excelente',
        Great: 'Estupendo',
        Good: 'Bueno',
        Average: 'Promedio',
        Poor: 'Pobre',
        'Submit': 'Enviar',
        complete: 'Presentación Completa'
      },
      zh: {
        'First Name': '名字',
        'Last Name': '姓',
        'Enter your first name': '输入你的名字',
        'Enter your last name': '输入你的姓氏',
        'When did you start using the Form.io platform?': '您是什麼時候開始使用 Form.io 平台？',
        'Enter the date': '輸入日期',
        'How would you rate the Form.io platform?': '你如何评价Form.io平台？',
        'How was Customer Support?': '客户支持如何？',
        'Overall Experience?': '总体体验？',
        Survey: '调查',
        Excellent: '优秀',
        Great: '大',
        Good: '好',
        Average: '平均',
        Poor: '错',
        'Submit': '提交',
        complete: '提交完成'
      },
      ar: {
        'First Name': 'الاسم الأول',
        'Last Name': 'اسم العائلة',
        'Enter your first name': 'أدخل اسمك الأول',
        'Enter your last name': 'أدخل اسم عائلتك',
        'When did you start using the Form.io platform?': 'متى بدأت باستخدام منصة Form.io؟',
        'Enter the date': 'أدخل التاريخ',
        'How would you rate the Form.io platform?': 'كيف تقيم منصة Form.io؟',
        'How was Customer Support?': 'كيف كان دعم العملاء؟',
        'Overall Experience?': 'التجربة العامة؟',
        Survey: 'استبيان',
        Excellent: 'ممتاز',
        Great: 'رائع',
        Good: 'جيد',
        Average: 'متوسط',
        Poor: 'ضعيف',
        'Submit': 'إرسال',
        complete: 'تم الإرسال'
      }
    }
  }).then(function(form) {
    window.setLanguage = function(lang) {
      form.language = lang;
      document.body.setAttribute("dir", lang === "ar" ? "rtl" : "ltr"); // Switch direction
    };
  });
```

{% hint style="info" %}
**Right-to-left language support**

In the above example, note the `setAttribute()` element used to accommodate languages rendered in a right-to-left direction. Include any additional language codes that may need to be rendered this way.
{% endhint %}

This code within a JSFiddle will work as follows:

{% embed url="<https://jsfiddle.net/TanyaFormio/buyht194/>" %}

## Dynamic Translations using Resources

The above example s not dynamic and requires an application change in order to introduce new translations. Make the translations dynamic using Form.io Resources so that any non-developer can contribute to the translation process. This can be achieved using the following method:

### Create a Language Resource

The first step is to create a Language resource within your Project, called **Language.** Within this resource, add the following fields:

* A **Select** Field for the Language Code.\
  For the **Data Source**, use *Values,* and provide the language as the **Label.**\
  Then, add the lang-code as the value as seen:

![](/files/brpGAC8eD0WzTx2sHTsk)

* A **Data Map** component, which contains a *Translation* **Text Field** like the following:

![](/files/W78nneheTbduX0lT5tNv)

The completed resource will look like the following:

![](/files/9I5PCdsmsWTeAZbfmuzP)

Now press **Create Resource** button to create the new Resource.

Once this is created, use the resource to create a new submission for each translation. The following example illustrates the fields for Español:

![](/files/843dj9GcaWLAE3M5KhBq)

Create the submission to add the "language".\
This will be used to manage all of the translations in a standard way. Input the rest of the language translations the same way until there are multiple to choose from.

#### Language Resource "Read All Submissions" Access

For most applications, the end user will be authenticated when they are switching between languages. In some cases, the user may be anonymous. As with any resource, ensure that the proper Role has access to the *Read All Submissions* permission within the **Access** section of the Language form.

### Dynamic Language Controller

Now that there is a language resource with the correct access, write the logic that will perform the dynamic language display. The form controller that establishes a dynamic language is pretty simple.\
It will send an API call to the form resource submission API (where the user should have "read all" submission access) to fetch the Submission that is associated with the language that was chosen.\
Implement some in-memory cache to reduce re-fetching the submissions as the user clicks between different languages. Put most of the logic within the `window.setLanguage` method used above. Here is what the Form Controller should look like:

```javascript
var languages = {en: true};
window.setLanguage = function(lang) {
  // If we already have loaded the language, then just set it with the sdk.
  if (languages[lang]) {
  	return form.language = lang;
  }
  
  // Fetch the language from the Resource.
  Formio.fetch('https://formiodata.form.io/language/submission?data.language=' + lang).then(function(resp) {
	  return resp.json();
  }).then(function(result) {
    // Ensure future sets will use the cached language.
  	languages[lang] = true;
  
    // Add this language.
    form.addLanguage(lang, result[0].data.translations);
    
    // Set this language.
    form.language = lang;
  });
};
```

Here is a JSFiddle demonstrating this dynamic loading system working:

{% embed url="<https://jsfiddle.net/TanyaFormio/8fu9d603/>" %}

## Custom Error Translation

Different error messages may be used based on what the current language is. You can achieve this by setting the i18n translations in the application. Below is an example of how to add translations to custom error messages

1. Start by creating a new form.
2. Add a **Text Field** to the form.
3. Open **Settings > Validation > Custom Validation** add the following code:

`valid = input === 'example' ? true : 'mycustomerror';`

4. In the application, create the form above and add translations for the error message. The code should look something like the following:

```
Formio.createForm(document.getElementById('formio'), {
                components: [
                    {
                        "label": "Text Field",
                        "applyMaskOn": "change",
                        "tableView": true,
                        "validate": {
                            "custom": "valid = input === 'example' ? true : 'mycustomerror';"
                        },
                        "validateWhenHidden": false,
                        "key": "textField",
                        "type": "textfield",
                        "input": true
                    }
                ]
            }, {
                language: 'es',
                i18n: {
                    en: {
                        "mycustomerror": 'Your name must be example'
                    },
                    es: {
                        "mycustomerror": 'Tu nombre debe ser ejemplo.'
                    }
                }
            })
```

At this point, error message language will be set based on what the current language is.

{% hint style="info" %}
To interpolate data from the form, use the {{}} notation. For example, to interpolate the current input being typed in, change 'Your name must be example' to 'Your name can't be {{data.textField}}'
{% endhint %}


# Form Evaluations

This section describes how the Form.io Renderer evaluates javascript code.

### JavaScript Evaluation

Within the renderer and builder code, it is possible write custom snippets of JavaScript to perform custom actions that would otherwise be difficult to configure though standard configuration.\
These snippets of JavaScript are introduced through Form Builder interface, through options like Custom Default Value, Calculated Values, Logic, as well as many others.

These snippets are viewed and edited through a special JavasSript editor within the Form Builder. The editor provides a review of the variables available within the execution context, as seen here:

<figure><img src="/files/P2szjLyLG2Dp6upE0K8K" alt=""><figcaption><p>JavaScript evaluation within the form builder.</p></figcaption></figure>

### Evaluation Context

For every JavaScript evaluation that occurs, there are a number of variables that are presented within the execution sandbox. These variables are commonly referred to as the **evalContext** variables. Some of the evaluations provide their own evalContext (which are documented separately), however the following eval variables tare common across all evaluation types:

| Variable      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Example                                                                                                                                                                                                                                                                                                    |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| form          | The complete [**Form JSON**](/dev/form-development/form-renderer#rendering-form-json) schema of the form.                                                                                                                                                                                                                                                                                                                                                                                   | <p><code>{</code></p><p><code>"\_id": "....",</code></p><p><code>"path": "user",</code></p><p><code>"name": "user",</code></p><p><code>"display": "form",</code></p><p><code>"components": \[</code></p><p><code>{</code></p><p><code>...</code><br><code>}</code><br><code>]</code><br><code>}</code></p> |
| submission    | The complete [**Submission JSON**](/dev/form-development/form-renderer#submission-data) of the current submission for the rendered form.                                                                                                                                                                                                                                                                                                                                                    | <p><code>{</code><br><code>"data": {</code><br><code>"first": "Joe",</code><br><code>"last": "Smith"</code><br><code>},</code><br><code>"metadata": {}</code><br><code>}</code></p>                                                                                                                        |
| component     | The current Component JSON schema.                                                                                                                                                                                                                                                                                                                                                                                                                                                          | <p><code>{</code><br><code>"type": "textfield",</code><br><code>"label": "Name",</code><br><code>"key": "name"</code><br><code>}</code></p>                                                                                                                                                                |
| value         | The current component value.                                                                                                                                                                                                                                                                                                                                                                                                                                                                | `show = value === 5;`                                                                                                                                                                                                                                                                                      |
| instance      | <p>This points to the component instance. This is helpful if you wish to gain access to the actual component instance object to perform special functions and execute certain methods of the component.<br><br>Go to <a href="https://github.com/formio/formio.js/blob/master/src/components/_classes/component/Component.js"><strong><https://github.com/formio/formio.js/blob/master/src/components/_classes/component/Component.js></strong></a> to see what methods you can access.</p> | `valid = instance.checkValidity()`                                                                                                                                                                                                                                                                         |
| self          | Alias of "instance"                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                                                                                                                                                                                                                                                                                            |
| instance.root | This always points to the form instance that contains the component. This is helpful if you wish to reference other components using the following code.                                                                                                                                                                                                                                                                                                                                    | `instance.root.getComponent('email') = 'joe@example.com';`                                                                                                                                                                                                                                                 |
| options       | The [**Form Renderer Options**](/dev/form-development/form-renderer#form-renderer-options) passed to the renderer.                                                                                                                                                                                                                                                                                                                                                                          | <p><code>{</code><br><code>"i18n": {</code><br><code>"language": "es",</code><br><code>"es": {</code><br><code>...</code><br><code>}</code><br><code>}</code><br><code>}</code></p>                                                                                                                        |
| data          | The root data context for the renderer. This will always point to the full data object from "submission.data"                                                                                                                                                                                                                                                                                                                                                                               | <p><code>{</code><br><code>"first": "Joe",</code><br><code>"last": "Smith",</code><br><code>"children": \[</code><br><code>{</code><br><code>"first": "...",</code><br><code>"last": "..."</code><br><code>}</code><br><code>]</code><br><code>}</code></p>                                                |
| row           | The "row" variable is a special "context" data object that points to the current data "context" of the component. This changes based on what component we are referring to. For example, if you are within a DataGrid component (which is an array of objects), the "row" will point to the current row object.                                                                                                                                                                             | <p>Let's suppose you have a DataGrid called Children, and you wish to write javascript to validate the birthday component within the children DataGrid. You would be able to use "row" to point to the "current" row's birthday field like the following.<br><br><code>row\.birthday</code></p>            |
| rowIndex      | This is the index for the current row you are on. For DataGrid and EditGrid components, this is a number where 0 means we are on the first row, 1 means we are on the second row, etc.                                                                                                                                                                                                                                                                                                      | <p>0 - first row</p><p>1 - second row</p><p>...</p>                                                                                                                                                                                                                                                        |
| t             | A function, which is used to translate certain strings using the [**Translation**](/dev/form-development/translations#rendering-translations) system.                                                                                                                                                                                                                                                                                                                                       | `value = t('First Name');`                                                                                                                                                                                                                                                                                 |
| \_            | An instance of Lodash which can be used to simplify certain operations within your javascript code.                                                                                                                                                                                                                                                                                                                                                                                         | `value = _.get(data, 'a.b')`                                                                                                                                                                                                                                                                               |
| utils         | An instance of the [**Form Utilities**](/dev/javascript-development/javascript-utilities#utility-functions).                                                                                                                                                                                                                                                                                                                                                                                | <p><code>utils.eachComponent(component.components, function(component) {</code><br><code>...</code><br><code>});</code></p>                                                                                                                                                                                |
| util          | Alias of "utils"                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |                                                                                                                                                                                                                                                                                                            |
| user          | The currently authenticated User object.                                                                                                                                                                                                                                                                                                                                                                                                                                                    | `value = user.data.email;`                                                                                                                                                                                                                                                                                 |
| token         | The current JWT token for the authenticated user.                                                                                                                                                                                                                                                                                                                                                                                                                                           |                                                                                                                                                                                                                                                                                                            |
| moment        | An instance of the [**Moment.js**](https://momentjs.com/) library.                                                                                                                                                                                                                                                                                                                                                                                                                          | `valid = moment.diff(value, '12/5/2021') > 0;`                                                                                                                                                                                                                                                             |
| config        | The current [**Public Configuration**](https://help.form.io/admin/projects#public-configuration) config that has been added to the form json.                                                                                                                                                                                                                                                                                                                                               |                                                                                                                                                                                                                                                                                                            |

#### Custom Evaluation Context Variables

In addition to having the standard variables as shown above, it is possible to also introduce your own evaluation context variables that can be used within the evaluations. This is very helpful in case you have pre-defined methods for validations, etc. that you would like to expose to all of the evaluations. This can be achieved using either the Form Module found in your Project Settings, or through the embedding of the form.

**Form Module Example**

Within your Project Settings, click on Settings > **Custom JS and CSS.** Within this section, you will see a section called **Form Module** which is used to write a snippet of JSON that is able to dynamically configure the form as it is being embedded within an application. You can introduce a new context variable as follows.

```
{
  options: {
    form: {
      evalContext: {
        validatePhone: function(input) {
          return input.match(/^[2-9]\d{2}-\d{3}-\d{4}$/);
        }
      }
    }
  }
}

```

With this example, there would now be a new method available in the evaluation context called "validatePhone" and could be used as follows within a Custom Validation block.

```
valid = validatePhone(input) ? true : 'Phone number is invalid';
```

**Form Embedding Example**

You can also set custom evaluation context variables when you embed the form. The following shows an example of how this could be done.

```
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  evalContext: {
    validatePhone: function(input) {
      return input.match(/^[2-9]\d{2}-\d{3}-\d{4}$/);
    }
  }
})
```

This can then be used in the same way as described above.

Now that we have an understanding of evaluation contexts, let's discuss all the different places where javascript evaluations can be performed. There are many sections that allow for JavaScript evaluation. These sections are described as follows.

### Custom Default Value

This provides a way to set the custom default value of the component you are currently configuring. The default value is the value that is used at the initialization of the component and provides you an opportunity to set the initial value of the component, but also provides a good point to place any initialization code you may wish to add to the component.

**Additional Evaluation Context**

For custom default values, there are a few additional evaluation context variables that are used.

| Variable | Description                                   | Example      |
| -------- | --------------------------------------------- | ------------ |
| value    | The value to set as the custom default value. | `value = 5;` |

**Example 1: Set custom default value to the combination of other fields.**

```
value = data.firstName + " " + data.lastName;
```

**Example 2: Listen for change events of this component and set the value of another component**

```
instance.on('change', function(event) {
  if (
    event && 
    event.changed && 
    event.changed.component && 
    event.changed.component.key === component.key) 
  {
    instance.root.getComponent('email') = instance.getValue() + '@example.com';
  }
});
```

### Calculated Value

The calculated value snippet allows you to write custom pieces of javascript that set the value of a component. The value is set by setting the variable "value" within the snippet of javascript.

**Additional Evaluation Context**

For calculated values, there are a few additional evaluation context variables that are used.

| Variable | Description                               | Example      |
| -------- | ----------------------------------------- | ------------ |
| value    | The value to set as the calculated value. | `value = 5;` |

**Example 1: Perform a Total Amount calculation on values in a data grid**

Assuming that there is a Data Grid component called "Scores" that contains a component within the data grid called "Score", you could have a component outside of the data grid, called "Total" with the following calculated value.

```
value = data.scores.reduce(function(total, row) {
  return total + row.score;
}, 0);
```

**Example 2: Conditionally calculate a value**

You can also choose to set the value within an if statement, and this would only set the value under certain conditions. For example, this could be used to force a "maximum" value.

```
if (instance.getValue() > 10) {
  value = 10;
}
```

### Custom Validation

Custom Validations allow you to write a snippet of JavaScript that decides how the component should be validated as well as what error to show when the evaluation is determined to be invalid. This can be achieved using the following additional context variables exposed to the custom validation section.

**Additional Evaluation Context**

For calculated values, there are a few additional evaluation context variables that are used.

| Variable | Description                                                                                                                                                                                                                              | Example                                                |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| input    | The value that has been input into the component that is being compared for evaluation.                                                                                                                                                  | `valid = input === 5;`                                 |
| valid    | A special variable that determines if the component is valid. If the value is set to "true", then the component is valid. Otherwise you would set the value of "valid" to the string you would like to show the user when it is invalid. | `valid = input === 5 ? true : 'The value must be 5!';` |

**Example 1: Validate that this "validate password" field matches the "password" field.**

```
valid = input === data.password ? true : 'Passwords must match!';
```

### Advanced Conditions

Advanced conditions allow you to write a snippet of Javascript that determines the visibility/validation condition for the component. When the value of a conditional is set to false, the component effectively becomes "inactive" which means it is both not included visibly in the form, but also is not evaluated for validity. This is commonly used to present different sections of the form based on the answers provided by other fields.

**Additional Evaluation Context**

For advanced conditions, there are a few additional evaluation context variables that are used.

| Variable | Description                                                                                                                                                                                                                                                                       | Example                       |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| show     | Determines if this component is visible or not. If show is equal to "false", then the component not only becomes invisible, but also is no longer evaluated for validity. For example, if the field is required, but is conditionally not visible, then it no longer is required. | `show = value === 'Testing';` |
| value    | The current value of the component that is being compared for evaluation.                                                                                                                                                                                                         | show = value === 5;           |

### Logic: JavaScript Trigger

Within the Logic tab, there is an ability to add Logic to your forms to perform different operations such as hiding the component, making it required, etc under certain conditions. The triggers for logic determine how the current logic section is triggered.

**Additional Evaluation Context**

For calculated values, there are a few additional evaluation context variables that are used.

| Variable | Description                                                                                                                                     | Example                                    |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| result   | Determines if the logic section should be triggered. If result is set to "true" it will be triggered, if it is set to "false", then it will not | `result = data.email === 'admin@form.io';` |

**Example 1: Trigger the logic if the average grades are less than 70**

```
var total = data.grades.reduce((total, grade) => total + grade, 0);
var average = total / data.grades.length;
result = average < 70.0;
```

### Logic: Custom Actions

Within the Logic, after a logic section has been triggered, it will now perform the "action" of that logic. This is the "do something" part of the logic section where it performs an operation. Within this section, it is possible to write your own javascript to perform the action you would like to perform within the action.

**Example 1: Set the component value when the value executes.**

```
value = data.score1 + data.score2;
```

## JSON Logic

Within every evaluation type, there is also the ability to configure the evaluations using JSON schemas. This is helpful if you wish to perform complex evaluations without the requirement of executing the JavaScript "eval" necessary to perform the javascript evaluations of the scripts shown above.

{% hint style="info" %}
There are other options for not using "eval" such as using the protected eval plugin described below, but JSON Logic also serves as a good strategy for such protections.
{% endhint %}

The JSON Logic system uses the [**JSON Logic Library**](https://jsonlogic.com/) to perform the evaluations needed for each of the evaluation sections. Below are some examples of the different evaluation types on how this system can be used to create complex evaluations without using any JavaScript.

#### Custom Default Value

**Example 1: Concatenate the value of two different components string values together.**

```json
{"cat": [{"var": "data.firstName"}, " ", {"var": "data.lastName"}]}
```

#### Calculated Value

**Example 1: Sum together a multiple value number component**

```json
{"_sum": {var: "data.multinumber"}}
```

#### Custom Validation

For custom validations, you need to always use the "if" parameter within JSON Logic. The first argument to the "if" statement is the "true" case, and the second should be the error that you show when the value is not set. The following shows examples of how this is used.

**Example 1: Validate if a string is equal to a value.**

```json
{
  "if": [
    {
      "===": [
        {
          "var": "input"
        },
        "Bob"
      ]
    },
    true,
    "Your name must be 'Bob'!"
  ]
}
```

**Example 1: Validate if an email is from a certain domain**

```json
{
  "if": [
    {
      "in": [
        {
          "var": "input"
        },
        "form.io"
      ]
    },
    true,
    "The email must be from 'form.io'!"
  ]
}
```

## JavaScript Evaluator

While the Form.io platform offers a large amount of flexibility with the evaluations and executions of scripts within the renderer, it also includes even more flexibility and extensibility through the use and modification of the **Evaluator** within the renderer.

The Evaluator is a static class object where all javascript executions pass through to be evaluated. The code for the basic Evaluator class can be found at the following code.

{% embed url="<https://github.com/formio/formio.js/blob/master/src/utils/Evaluator.js>" %}
The Form.io Evaluator class
{% endembed %}

This class is used to perform any executions and 'eval' processes within the renderer from template rendering to the execution of javascript snippets within the renderer. The instance can also be referenced within your application by simply accessing the following property on the global Formio object.

```
Formio.Evaluator
```

Using this instance, you can easily configure how the Evaluator behaves such as the following describes.

### Configuring the Evaluator

There are many ways that you can use the instance of the Evaluator to modify how it behaves by default. Some of these ways are described below:

#### Turn off evaluations

The first thing you may wish to do is completely disable all evaluations from occurring. You would want to do this if you are running the renderer within a tight security environment where you may not trust the form builders who created the form, and worry about the execution of malicious JavaScript within your application. This can be done by setting the **noeval** property to true like so.

```javascript
Formio.Evaluator.noeval = true;
Formio.createForm(document.getElementById('formio'), ...);
```

#### Changing the template evaluation settings

The evaluator is also used to evaluate all templates and perform interpolations, such as the following.

```
Your first name: {{ data.firstName }}
```

This string may be contained within an HTML Element component within the form, but since it contains a token, it will be interpolated using the **evalContext** as described in the section above. It is possible to change the format of all of these templates to use a different syntax. For example, if you wish to change it to the following.

```
Your first name: <% data.firstName %>
```

you could use the templateSettings property of the Evaluator to accomplish this goal.

```javascript
Formio.Evaluator.templateSettings = {
  evaluate: /\{%([\s\S]+?)%\}/g,
  interpolate: /\<\%([\s\S]+?)\%\>/g,
  escape: /\{\{\{([\s\S]+?)\}\}\}/g
};
```

These settings are described as follows.

* **evaluate**: This is the template for string "evaluations" where it executes the javascript within. This requires that you have evaluations turned on by ensuring the "noeval" flag is not set or set to false.
* **interpolate**: This is where you can provide "interpolated" replacement values based on the values provided by the evalContext. For example `{{ data.email }}` will replace that token with the value from "data" with the key of "email"
* **escape**: This configuration tells the interpolation how to find "escaped" tokens. For example, if you wish to actually display `{{ data.email }}` and do not wish for it to be interpolated, then you will use the following string. `\{\{ data.email \}\}`

### Overriding the Evaluator

In addition to providing configurations for the Evaluator, it is also possible to perform overrides to inject your own custom code into how evaluations are performed. This can be done by injecting your own methods into the Evaluator that "inject" your own code into a method.

As a quick example of something that could be done, let's suppose you wish to `console.log` all evaluations that were being performed within the renderer, the following code could be used to "inject" this into the renderer evaluation execution.

```javascript
var evaluate = Formio.Evaluator.evaluate;
Formio.Evaluator.evaluate = function(func, args) {
  console.log(func, ...args);
  return evaluate(func, args);
}
```

This method shows how you can save off the original function as a variable, then override the method, and then use that original saved function as the function you return with the evaluation. This allows you to inject your own console.log into the process so that you can understand all evaluations that are being executed.

The following methods can be overridden:

* **`evaluator(func, ...params)`** - Returns a method of evaluation. By default, this returns a new function that will be evaluated at a later time.
* **`template(template, hash)`** - Converts a string into a template function that will be executed later.
* **`interpolate(rawTemplate, data, _options)`** - Accepts a string template, along with data context variables, and returns the interpolated result string.
* **`evaluate(func, args)`** - Executes the evaluator function (above) with the arguments provided.

#### Example: Override Evaluator to work with Node.js VM2

A very good example of how to override the Evaluator can actually be found within our Open Source server code which overrides the evaluator to perform all javascript evaluations within a VM on the server to protect against malicious code. This code in complete form can be found @ [**https://github.com/formio/formio/blob/master/src/util/util.js#L56**](https://github.com/formio/formio/blob/master/src/util/util.js#L56)

Here is a snippet that shows how the evaluator can integrate with VM2.

<pre class="language-javascript"><code class="lang-javascript">const {VM} = require('vm2');
const vm = new VM({
  timeout: 250,
  sandbox: {
    result: null,
  },
  fixAsync: true
});

<strong>Formio.Evaluator.noeval = true;
</strong>Formio.Evaluator.evaluator = function(func, args) {
  return function() {
    let result = null;
    /* eslint-disable no-empty */
    try {
      vm.freeze(args, 'args');

      result = vm.run(`result = (function({${_.keys(args).join(',')}}) {${func}})(args);`);
    }
    catch (err) {}
    /* eslint-enable no-empty */
    return result;
  };
};
</code></pre>

This code does a couple of things.

1. It turns off any normal evaluations by setting "noeval" to true.
2. It creates a new VM to perform any javascript executions within.
3. It overrides the "evaluator" method to execute the script within a VM and return the result. It also ensures that the ONLY variables that the script has access to within the VM are those provided by the evalContext.

### Custom Evaluators

In addition to overriding the base Evaluator, the renderer also enables the ability to create your own Evaluator class and register it as the new evaluator for the renderer, this documentation shows you how this can be done.

#### Building your own custom evaluator

Very similar to overriding the methods described above, it is possible to completely write your own Evaluator class, and then register that Evaluator as part of the renderer. In order to accomplish this, you will need to provide implementation to a few methods that are called from the renderer, which is defined below.

```javascript
const CustomEvaluator = {
  /**
   * Takes a string function and returns an evaluator that will perform the execution.
   *
   * @param func - This is the string representation of the function that will be executed.
   * @param params - A spread of parameters that are being passed to the function to be executed.
   *
   * @return - This function should return a method that will then be passed to the "evaluate" method of this class. 
   */
  evaluator(func, ...params) {
  },
  
  /**
   * Takes a template string, and then returns a template function that will be executed later with evalContext variables.
   *
   * @param template - A string of the template that needs to be turned into a template function.
   *
   * @return - The template function that will be executed in the future with the evalContext variables.
   */
  template(template) {
  },
  
  /**
   * A method that takes a string, and some data, and then returns the interpolated result of that string.
   *
   * @param rawTemplate - The string version of the template that should be interpolated.
   * @param data - The data that will be passed to the interplation.
   * @param options - Configuration options to use when interplating.
   *
   * @return - A string that has been interpolated. 
   */
  interpolate(rawTemplate, data, options) {
  },
  
  /**
   * Perform an evaluation
   *
   * @param func - The function that was returned by the "evaluator" method.
   * @param args - The function arguments to be passed to the evaluation function.
   *
   * @return - The result of the execution.
   */
  evaluate(func, args) {
  }
};
```

Once you have implemented your own Evaluator class, you can then register this class using the `registerEvaluator` method as follows.

```javascript
Formio.Evaluator.registerEvaluator(CustomEvaluator);
```

It is also possible to create a Form.io module, and include your custom evaluator within the export of your module as follows.

```javascript
export default {
    evaluator: CustomEvaluator
}
```

Then, someone can implement your evaluator by simply using the module as follows.

```javascript
import { Formio } from '@formio/js';
import EvaluatorModule from 'yourevaluator';
Formio.use(EvaluatorModule);
```

#### Protected Evaluator

This library can be installed and used as follows.

```
npm install --save @formio/protected-eval
```

```javascript
import ProtectedEval from '@formio/protected-eval';
import { Formio } from '@formio/js';
Formio.use(ProtectedEval);
```

There are some differences in using this evaluator that need to be understood, so please read more information about this evaluator by going to the following Github repo.

{% embed url="<https://github.com/formio/protected-eval>" %}


# Protected Evaluator

The **Protected Evaluator** is a custom evaluator offered by Form.io to protect against the execution of unsafe, user-supplied code.

The Protected Evaluator is available for use on the Form.io Github: [**https://github.com/formio/protected-eval**](https://github.com/formio/protected-eval)

The Protected Evaluator is based on the open source [JS Interpreter module.](https://github.com/NeilFraser/JS-Interpreter)

### Why use the Protected Evaluator?

Since many Form.io components can be customized with JavaScript written by Form Builders, application owners may want to evaluate such code in a protected environment by using the Protected Evaluator.

The Evaluator is a static class object that all JavaScript executions pass through to be evaluated, and thus offers a degree of protection against malicious code in component customization.

#### What customizations might require the Protected Evaluator?

Some of the customizations that may require a form to use the Protected Evaluator are:

* Conditional logic
* Calculated fields
* Custom validation
* Custom default values

These customizations often use code introduced by the Form Builder. Security practices may require the use of Protected Eval when such customizations are used.

### How to use the Protected Evaluator

To use the Protected Evaluator:

1. Install the module by using the following command:

```
npm install --save @formio/protected-eval
```

2. Import the Protected Evaluator into the application by adding the following code:

```javascript
import ProtectedEval from '@formio/protected-eval';
import { Formio } from '@formio/js';
Formio.use(ProtectedEval);
```

### Operational Impact

Protected Evaluation executes the user-supplied JavaScript on a line-by-line basis in a sandboxed environment. This necessarily introduces a degree of overhead that can affect the performance of a form. This overhead will scale linearly with the amount of custom code. As a result, forms that make significant use of calculated values, custom default values, conditional logic, etc. may see a noticeable degradation in performance.

#### Mitigating effect on performance

Every particular use case may need to find a unique balance between security and performance. In cases where performance cannot be sacrificed, some design patterns may be useful when mitigating the impact on performance:

* **Custom evaluator -** The Protected Evaluator takes a blanket approach to sandbox all custom JavaScript. If there are specific concerns that can be addressed with a more targeted evaluator, Form.io makes it easy to develop and integrate a [custom evaluator](/dev/form-development/form-evaluations#custom-evaluators).
* **Offloading logic** - In some cases, the customization done in the Form.io component can be offloaded to other aspects of the application. This reduces the need to invoke the Protected Evaluator as frequently.


# The Security Module

The Security Module is an optional add-on to your subscription comprised of a collection of features and reporting options available to Form.io users. If you're seeking more robust security capabilities in your deployed environment such as audit logging, data encryption, and container scanning, this package is perfect for you.

{% hint style="info" %}
Contact <sales@form.io> for more information about the Security Module
{% endhint %}

Below are the features and details included in the Security Module. **Follow the links** for more information:

### [Advanced Audit Logging](https://help.form.io/dev/audit-logging)

Server logs for more information on who, what, & when things occurred.

### [Action Logs](/form-building/actions#action-logs)

Logs for more information on who, what, & when things occurred as it pertains to Form Actions.

### [Form Revisions](/form-building/form-revisions)

Extend the capabilities of any project cycle by giving users the ability to evolve current forms while preserving the integrity of previous iterations.

### [Submission Revision Logs](/form-building/submissions#enable-form-versioning-1)

Track changes to Submission Data and output a PDF audit log document of record for changes made to submission data.

### [Submission Collections](/form-building/submissions#submission-collection)

Enables the storage of submission data within a separate database collection, which ensures data separation between collections.

### [Field Level Encryption](https://help.form.io/form-building/components/component-settings#encrypted)

Form.io ensures the security of sensitive data through a multi-layered approach to encryption. At the foundational level, Form.io runs on MongoDB, and when using MongoDB Atlas, encryption at rest and in transit is provided by default, using advanced encryption standards to ensure that all data is protected at multiple layers.\
\
Building on this foundation, Form.io adds an additional layer of security through its encrypted fields functionality. This process leverages the robust aes-256-cbc algorithm, a symmetric encryption method known for its high level of security.\
To perform the encryption and decryption, Form.io utilizes the OpenSSL library via Node.js. Leveraging OpenSSL allows Form.io to securely encrypt data before storing it and decrypt it when necessary, ensuring that sensitive information remains protected throughout its lifecycle. The use of aes-256-cbc ensures that data is encrypted with a 256-bit key, providing a strong defense against unauthorized access.

### Container Security Scanning

Guaranteed Container scanning using [**Snyk**](https://snyk.io/what-is-snyk/).


# Form Templates

Describes the Form.io Form Templating System

The Form.io templating system allows developers to modify the look-and-feel of their organization's forms by exposing APIs that can inject custom CSS classes into specific elements in a component or can change the underlying HTML structure of a component entirely. You can either create an entire template for all components, or simply override existing templates if you wish to just alter a few of the components.

Form.io currently maintains two open source framework templates:

* Bootstrap - [**https://github.com/formio/bootstrap**](https://github.com/formio/bootstrap3)
* United States Web Design System (USWDS) - [**https://github.com/formio/uswds**](https://github.com/formio/uswds)

There are some additional templates that have been developed by our open source community:

* UK Government Design System - [**https://github.com/DigitalPatterns/formio-gds-template**](https://github.com/DigitalPatterns/formio-gds-template)
* Bulma - [**https://github.com/formio/bulma**](https://github.com/formio/bulma)

## What is a template?

In this document, a "component template" refers to the combination of an underlying DOM structure paired with CSS classes, inline styles, and other contextual state. The @formio/js rendering engine receives these component templates in the form of pre-compiled functions that return HTML strings; these functions are then called when the components are rendered to the DOM.

A "template" in this document refers to a collection of component templates. Examples of templates are [the Form.io Bootstrap template](https://github.com/formio/bootstrap) and [the Form.io USWDS template.](https://github.com/formio/uswds)

## Framework Templates

By default, the @formio/js renderer uses [the Form.io Bootstrap 5-based template.](https://github.com/formio/bootstrap) To use another template, import the template object and pass it as an argument to `Formio.use`.

```js
import { Formio } from '@formio/js';
import { bootstrap4 } from '@formio/bootstrap';

// use the Bootstrap 4-based template instead of the default
Formio.use(bootstrap4);
```

```javascript
import { Formio } from '@formio/js';
import uswds from '@formio/uswds';

// use the USWDS-based template instead of the default
Formio.use(uswds);
```

## Overriding Templates at Runtime

In addition to setting the global CSS Framework, you can override specific component templates within that framework by modifying the global `Templates` object at runtime. Each component template consists of a group of pre-compiled functions that return HTML strings. Each of these pre-compiled functions corresponds to a render mode, but for the purposes of this document we will focus on the most common, the "form" render mode.

```javascript
import { Templates } from '@formio/js';

// override the "input" component template (used by components that contain a text input)
const myInput = (ctx) => `<div class="${ctx.component.type}">${ctx.value}</div>`;
Templates.current.input.form = myInput;
```

```javascript
import { Templates } from '@formio/js';

// override the "input" and "html" component templates
Templates.current = {
  input: {
    form: (ctx) => '<div>My custom template</div>'
  },
  html: {
    form: (ctx) => '<div>My other custom template</div>'
  }
};
```

### Overriding Specific Templates

Component templates are often consumed by multiple components. For example, the `input` template is consumed by components that contain a text input element; any overrides to the `input` template therefore could affect many of components in a form. To enable overriding a specific component template in a form, Form.io namespaces each component with its type and its key. For example, given a form with a `firstName` Text Field component and a `lastName` TextField component, you can:

* override each input component template<br>

  ```javascript
  Templates.current = {
    input: {
      form: (ctx) => '<div>Template Overridden!</div>'
    }
  };
  ```
* override only the Text Field component template using the template name (`"input"`) and the template type (`"textfield"`)<br>

  ```javascript
  Templates.current = {
    'input-textfield': {
      form: (ctx) => '<div>Template Overridden!</div>'
    }
  };
  ```
* override only the `firstName` component template using the template name (`"input"`), the template type (`"textField"`), and the component key (`"firstName"` )<br>

  ```javascript
  Templates.current = {
    'input-textfield-firstName': {
      form: (ctx) => '<div>Template Overridden!</div>'
    }
  };
  ```

{% embed url="<https://jsfiddle.net/brendanbond/6q851ytg/9/>" %}

## Render modes

In addition to "form" component templates, there are other render modes that allow for different representations of the same component.

The built-in render modes include:

* "form" - The default render to render as a form.
* "html" - Render the data as generic html, instead of a form.

Use [form options](/dev/form-development/form-renderer#form-renderer-options) to set the render mode:

```javascript
import { Form } from '@formio/js';

const form = new Form(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  renderMode: 'html'
});
```

You can also create your own render modes:

```javascript
import { Form, Templates } from '@formio/js';

Templates.current = {
  input: {
    myCustomRenderMode: (ctx) => '<div>bar</div>'
  }
};

const form = new Form(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  renderMode: 'myCustomRenderMode'
});
```


# The Form.io Standard Template

An easier way to customize your forms' look and feel.

{% hint style="info" %}
The Form.io Standard Template is in beta. Its APIs are subject to change.
{% endhint %}

Previously, there were two options for customizing the look and feel of your forms when they were rendered in your application.

1. You could use [the default Bootstrap 5-based template](https://github.com/formio/bootstrap) and [override Bootstrap directly](https://getbootstrap.com/docs/5.3/customize/overview/) in your application. This is a great option for Bootstrap-based applications, but forces applications that are not based on Bootstrap to include it as a dependency and also introduces the possibility of CSS collisions.
2. You could use the default Bootstrap 5-based template as a guide to writing your own template. This can be difficult; the component templates are written in an older templating syntax, and writing the DOM structure for components can require a deep knowledge of Form.io internals (e.g. [ref attributes](/dev/custom-components#template-references-refs)).

The Form.io Standard Template makes customizing the look and feel of the forms in your application easier by providing a default underlying HTML markup structure for each built-in component and exposing APIs that allow you to inject custom CSS class names into each component's constituent elements using JSON. This allows a more seamless integration with libraries like [TailwindCSS](https://tailwindcss.com/) without having to create an entire template from scratch.

## Getting Started

The Form.io Standard Template is available as an npm package.

```bash
npm install @formio/standard-template
```

The library exposes a function that you can use as a Form.io module.

```javascript
import { Formio } from '@formio/js';
import { standardTemplate, BOOTSTRAP_EXAMPLE } from '@formio/standard-template';

Formio.use(standardTemplate(BOOTSTRAP_EXAMPLE));
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform');
```

## How It Works

The Form.io Standard Template is a template - a collection of pre-compiled functions that return DOM strings - with no associated CSS classes. The CSS class names are provided by the user in the form of a JSON object that contains each component template along with each component template's constituent elements. For example, the `"input"` template includes things like the actual input element, the character count (for input-based components that have character count enabled), and the prefix/suffix (for input-based components with prefixes or suffixes enabled).

```
{
  /* ... */
  // the input component template
  "input": {
    // the "form" render mode
    "form": {
      // the input element and its CSS class names
      "input": ["form-control"],
      // the suffix and prefix
      "suffix": ["input-group-text"],
      "prefix": ["input-group-text"],
    /* ... */
    }
  }
  /* ... */
}
    
```

We've included a `BOOSTRAP_EXAMPLE` constant with the beta version of the Form.io Standard Template that you can use as a guide - it is a Standard Template-compatible JSON object that contains our Bootstrap 5 template class names.


# Translations

## Introduction

The Form.io Platform uses the [**i18Next**](https://www.i18next.com/) system as the mechanism for displaying all of the translations within the JavaScript Renderer and Builder. Refer to the i18Next documentation to understand all of the mechanisms that are available to handle translations within an application and forms rendered by Form.io. The Form.io Renderer exposes the i18next platform within the`i18next` variable in the renderer, and all options for this library can be introduced through the `i18n` configuration variable.

The following example illustrates how the i18next framework can be initialized and accessed within the Form.io renderer:

```javascript
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
    i18n: {...} // These options are passed to the i18Next framework
}).then((form) => {
    console.log(form.i18next); // Exposes the i18Next framework instance.
    
    form.language = 'es'; // Changes the language of the i18Next framework.
});
```

Following initialization, the features documented for the[ **i18Next framework**](https://www.i18next.com/) apply.\
\
The following topics provide additional guidance on rendering a form with internationalization:

## Rendering Translations

In order to provide translations to the renderer, introduce these translations using i18n configurations. There are also a few methods within the Form.io Renderer that can be used to change the language dynamically. For example, the following HTML code introduces buttons within the application that will trigger a language change:

```markup
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
<script src="https://cdn.form.io/js/formio.embed.js"></script>

<div class="btn-group">
  <button type="button" class="btn btn-primary" onclick="setLanguage('es')">Español</button>
  <button type="button" class="btn btn-secondary" onclick="setLanguage('en')">English</button>
  <button type="button" class="btn btn-info" onclick="setLanguage('zh')">中文</button>
  <button type="button" class="btn btn-success" onclick="setLanguage('ar')">العربية</button>
</div>

<div id="formio"></div>
```

After this, provide the following code to define the form, provide the translated text, and then dynamically change the text when the buttons have been clicked. The code will look as follows:

```javascript
Formio.createForm(document.getElementById('formio'), {
    components: [
      {
        type: 'textfield',
        key: 'firstName',
        label: 'First Name',
        tooltip: "Name",
        placeholder: 'Enter your first name',
        input: true
      },
      {
        type: 'textfield',
        key: 'lastName',
        label: 'Last Name',
        placeholder: 'Enter your last name',
        input: true
      },
      {
        label: 'When did you start using the Form.io platform?',
        tableView: false,
        datePicker: {
          disableWeekends: false,
          disableWeekdays: false,
        },
        enableMinDateInput: false,
        enableMaxDateInput: false,
        validateWhenHidden: false,
        placeholder: 'Enter the date',
        key: 'startDate',
        type: 'datetime',
        input: true,
        widget: {
          type: 'calendar',
          displayInTimezone: 'viewer',
          locale: 'en',
          useLocaleSettings: false,
          allowInput: true,
          mode: 'single',
          enableTime: true,
          noCalendar: false,
          format: 'yyyy-MM-dd hh:mm a',
          hourIncrement: 1,
          minuteIncrement: 1,
          time_24hr: false,
          minDate: null,
          disableWeekends: false,
          disableWeekdays: false,
          maxDate: null,
        }
      },
      {
        type: 'survey',
        key: 'questions',
        label: 'Survey',
        values: [
          { label: 'Great', value: 'great' },
          { label: 'Good', value: 'good' },
          { label: 'Poor', value: 'poor' }
        ],
        questions: [
          { label: 'How would you rate the Form.io platform?', value: 'howWouldYouRateTheFormIoPlatform' },
          { label: 'How was Customer Support?', value: 'howWasCustomerSupport' },
          { label: 'Overall Experience?', value: 'overallExperience' }
        ]
      },
      {
        type: 'button',
        action: 'submit',
        label: 'Submit',
        theme: 'primary'
      }
    ]
  }, {
    language: 'en',
    i18n: {
      es: {
        'First Name': 'Nombre de pila',
        'Name': 'Nombre',
        'Last Name': 'Apellido',
        'Enter your first name': 'Ponga su primer nombre',
        'Enter your last name': 'Introduce tu apellido',
        'When did you start using the Form.io platform?': '¿Cuándo empezaste a utilizar la plataforma Form.io?',
        'Enter the date': 'Introduce la fecha',
        'How would you rate the Form.io platform?': '¿Cómo calificaría la plataforma Form.io?',
        'How was Customer Support?': '¿Cómo fue el servicio de atención al cliente?',
        'Overall Experience?': '¿Experiencia general?',
        Survey: 'Encuesta',
        Excellent: 'Excelente',
        Great: 'Estupendo',
        Good: 'Bueno',
        Average: 'Promedio',
        Poor: 'Pobre',
        'Submit': 'Enviar',
        complete: 'Presentación Completa'
      },
      zh: {
        'First Name': '名字',
        'Last Name': '姓',
        'Enter your first name': '输入你的名字',
        'Enter your last name': '输入你的姓氏',
        'When did you start using the Form.io platform?': '您是什麼時候開始使用 Form.io 平台？',
        'Enter the date': '輸入日期',
        'How would you rate the Form.io platform?': '你如何评价Form.io平台？',
        'How was Customer Support?': '客户支持如何？',
        'Overall Experience?': '总体体验？',
        Survey: '调查',
        Excellent: '优秀',
        Great: '大',
        Good: '好',
        Average: '平均',
        Poor: '错',
        'Submit': '提交',
        complete: '提交完成'
      },
      ar: {
        'First Name': 'الاسم الأول',
        'Last Name': 'اسم العائلة',
        'Enter your first name': 'أدخل اسمك الأول',
        'Enter your last name': 'أدخل اسم عائلتك',
        'When did you start using the Form.io platform?': 'متى بدأت باستخدام منصة Form.io؟',
        'Enter the date': 'أدخل التاريخ',
        'How would you rate the Form.io platform?': 'كيف تقيم منصة Form.io؟',
        'How was Customer Support?': 'كيف كان دعم العملاء؟',
        'Overall Experience?': 'التجربة العامة؟',
        Survey: 'استبيان',
        Excellent: 'ممتاز',
        Great: 'رائع',
        Good: 'جيد',
        Average: 'متوسط',
        Poor: 'ضعيف',
        'Submit': 'إرسال',
        complete: 'تم الإرسال'
      }
    }
  }).then(function(form) {
    window.setLanguage = function(lang) {
      form.language = lang;
      document.body.setAttribute("dir", lang === "ar" ? "rtl" : "ltr"); // Switch direction
    };
  });
```

{% hint style="info" %}
**Right-to-left language support**

In the above example, note the `setAttribute()` element used to accommodate languages rendered in a right-to-left direction. Include any additional language codes that may need to be rendered this way.
{% endhint %}

This code within a JSFiddle will work as follows:

{% embed url="<https://jsfiddle.net/TanyaFormio/buyht194/>" %}

## Dynamic Translations using Form.io Resources

Translations can also be performed in a dynamic manner using the following method:

### Create a Language Resource

The first step is to create a Language resource within your Project, called **Language.** Within this resource, add the following fields:

* A **Select** Field for the Language Code.\
  For the **Data Source**, use *Values,* and provide the language as the **Label.**\
  Then, add the lang-code as the value as seen:

![](/files/brpGAC8eD0WzTx2sHTsk)

* A **Data Map** component, which contains a *Translation* **Text Field** like the following:

![](/files/W78nneheTbduX0lT5tNv)

The completed resource will look like the following:

![](/files/9I5PCdsmsWTeAZbfmuzP)

Now press **Create Resource** button to create the new Resource.

Once this is created, use the resource to create a new submission for each translation. The following example illustrates the fields for Español:

![](/files/843dj9GcaWLAE3M5KhBq)

Create the submission to add the "language".\
This will be used to manage all of the translations in a standard way. Input the rest of the language translations the same way until there are multiple to choose from.

#### Language Resource "Read All Submissions" Access

For most applications, the end user will be authenticated when they are switching between languages. In some cases, the user may be anonymous. As with any resource, ensure that the proper Role has access to the *Read All Submissions* permission within the **Access** section of the Language form.

### Dynamic Language Controller

Now that there is a language resource with the correct access, write the logic that will perform the dynamic language display. The form controller that establishes a dynamic language is pretty simple.\
It will send an API call to the form resource submission API (where the user should have "read all" submission access) to fetch the Submission that is associated with the language that was chosen.\
Implement some in-memory cache to reduce re-fetching the submissions as the user clicks between different languages. Put most of the logic within the `window.setLanguage` method used above. Here is what the Form Controller should look like:

```javascript
var languages = {en: true};
window.setLanguage = function(lang) {
  // If we already have loaded the language, then just set it with the sdk.
  if (languages[lang]) {
  	return form.language = lang;
  }
  
  // Fetch the language from the Resource.
  Formio.fetch('https://formiodata.form.io/language/submission?data.language=' + lang).then(function(resp) {
	  return resp.json();
  }).then(function(result) {
    // Ensure future sets will use the cached language.
  	languages[lang] = true;
  
    // Add this language.
    form.addLanguage(lang, result[0].data.translations);
    
    // Set this language.
    form.language = lang;
  });
};
```

Here is a JSFiddle demonstrating this dynamic loading system working:

{% embed url="<https://jsfiddle.net/TanyaFormio/8fu9d603/>" %}

## Custom Error Translation

Different error messages may be used based on what the current language is. You can achieve this by setting the i18n translations in the application. Below is an example of how to add translations to custom error messages

1. Start by creating a new form.
2. Add a **Text Field** to the form.
3. Open **Settings > Validation > Custom Validation** add the following code:

`valid = input === 'example' ? true : 'mycustomerror';`

4. In the application, create the form above and add translations for the error message. The code should look something like the following:

```
Formio.createForm(document.getElementById('formio'), {
                components: [
                    {
                        "label": "Text Field",
                        "applyMaskOn": "change",
                        "tableView": true,
                        "validate": {
                            "custom": "valid = input === 'example' ? true : 'mycustomerror';"
                        },
                        "validateWhenHidden": false,
                        "key": "textField",
                        "type": "textfield",
                        "input": true
                    }
                ]
            }, {
                language: 'es',
                i18n: {
                    en: {
                        "mycustomerror": 'Your name must be example'
                    },
                    es: {
                        "mycustomerror": 'Tu nombre debe ser ejemplo.'
                    }
                }
            })
```

At this point, error message language will be set based on what the current language is.

{% hint style="info" %}
To interpolate data from the form, use the {{}} notation. For example, to interpolate the current input being typed in, change 'Your name must be example' to 'Your name can't be {{data.textField}}'
{% endhint %}


# Accessibility Compliance Module

## **Overview**

The Accessibility Compliance Module is a separately licensable add-on to the Form.io Platform that supports developers in building forms that meet accessibility guidelines.

To get started using the Accessibility Compliance Module, go to the guide [Using the Accessibility Compliance Module](/dev/accessibility/using-the-accessibility-compliance-module).

For background information on the role of Form.io in application accessibility, refer to the section [About Accessibility and Webforms](/dev/accessibility/about-accessibility-and-webforms)

## What the Accessibility Compliance Module Delivers

The Accessibility Compliance Module allows developers to deliver a fundamentally different experience to end users of a form.

Some of those changes include:

* Forms exclusively use components that can be compatible with accessibility technology such as:
  * Screen readers.
  * Alternative input devices.
  * Alternative system displays.
* Modified visuals, such as high-contrast modes.
* Improved screen reader interaction:
  * Better descriptions of form components and fields
  * Announcements of field validation errors
* Accessible interaction with form components:
  * Keyboard (or alternative input device) navigation of wizard pages.
  * Keyboard (or alternative input device) selection within datepicker components.
* Improved focus order within forms, wizards, and form components.
* Modified display of form state:
  * Unified list of errors on form page.
  * Screen reader description of active/available wizard pages.

{% hint style="info" %}
While these features can be delivered through the use of the Accessibility Compliance Module, they are not automatic. Developers must intentionally design forms and the host application to deliver any accessibility features required.
{% endhint %}

## **How the Accessibility Compliance Module Modifies the Form.io Platform**

The module changes the platform at both the level of form building and form rendering.

#### **Form Builder with** Accessibility **Compliance Module**

The module restricts the components available to Form Builders, blocking the use of components that may not meet accessibility standards.

#### Form Renderer with Accessibility Compliance Module

The Accessibility Compliance Module overrides the default form renderer to change:

* Screen reader announcements of Form User action.
* Focus order/Focus trap/Focus placement
* Dynamic change of aria-attributes
* Validation messages handling
* Special styles for invalid/valid fields

#### Templates with Accessibility Control Module

Through the accessibility-focused USWDS template, or the standard Bootstrap template, the module supports:

* Proper HTML markup (every form field needs an associated label, correct component structure etc.)
* Aria-attributes such as aria-describedby, aria-labelledby, etc.
* Additional helpful messages for sighted users
* Additional instructions for non-sighted users (e.g. number types, etc.)
* WCAG compliant color contrasts (only applicable for USWDS for now)

## Where To Go Next

* [Using the Accessibility Compliance Module](/dev/accessibility/using-the-accessibility-compliance-module)
* [About Accessibility and Webforms](/dev/accessibility/about-accessibility-and-webforms)


# About Accessibility and Webforms

## The Role of Accessibility in Form.io

Forms necessarily require a degree of end-user interaction, which highlights the need to make that interaction accessible. Applications that require compliance with various accessibility standards and guidelines must be thoughtful about the design of the forms and the way those forms are presented within the application.\
Simply using form components rated to be compliant with accessibility standards does not ensure that the whole form is compliant. Additionally, an accessible form does not necessarily mean that the broader application is accessible.\
Application developers must evaluate the finished product holistically to determine the level of accessibility.

Form.io offers a variety of tools and best practices through the entire platform to support developers in implementing accessible applications.

## Accessibility Standards and Form.io

There are many standards used to evaluate the accessibility of an application. One of the most common standards is the [Web Content Accessibility Guidelines](https://www.w3.org/TR/WCAG21/), published by the World Wide Web Consortium (W3C). The current standard is WCAG 2.1.

WCAG 2.1 evaluates web accessibility based on several principles. When a Form.io component is described as being WCAG 2.1 compliant it means that component, when used according to best practices, will not interfere with a web application's WCAG 2.1 rating.

Additionally, the United States General Service Administration developed the [US Web Design System](https://designsystem.digital.gov/) (USWDS), a collection of standardized UI components and visual styles, to provide developers with a number of resources to aid in delivering accessible web applications and services.\
Form.io offers a USWDS [template](https://github.com/formio/uswds) that renders forms using markup and classes that are compatible with USWDS standards.


# Using the Accessibility Compliance Module

{% hint style="info" %}
The Accessibility Module uses a [Library License](/admin/licensing/library-licenses). Contact `sales@form.io` for information about acquiring a Library License.
{% endhint %}

## **Enabling the Accessibility Module**

The Accessibility Module must be imported and registered at the application level before it can be used, as seen in the following snippet:

```javascript
import { Formio } from '@formio/js';
import vpat from '@formio/vpat';

Formio.use(vpat);
```

## **Designing Accessible Forms**

Each Form.io component is evaluated for accessibility compliance based on how the component is presented within a standalone application.

When building forms using the Developer Portal [Form Builder](https://help.form.io/form-building/) or the [Enterprise Form Builder Module ](/dev/enterprise-form-builder-module)the following components met WCAG 2.1 accessibility standard during testing, and may be used to create fully accessible forms:

<table data-full-width="false"><thead><tr><th>Basic</th><th>Advanced</th><th>Layout</th><th>Data</th><th>Premium</th></tr></thead><tbody><tr><td>Text Field</td><td>Email</td><td>HTML</td><td>Hidden</td><td>Data Source</td></tr><tr><td>Text Area</td><td>URL</td><td>Content</td><td>Container</td><td>File</td></tr><tr><td>Number</td><td>Phone Number</td><td>Columns</td><td></td><td>Review Page</td></tr><tr><td>Password</td><td></td><td>Field Set</td><td></td><td></td></tr><tr><td>Checkbox</td><td>Day</td><td>Panel</td><td></td><td></td></tr><tr><td>Select Box</td><td>Time</td><td>Table</td><td></td><td></td></tr><tr><td>Select (Must use HTML5)</td><td>Currency</td><td>Well</td><td></td><td></td></tr><tr><td>Radio</td><td></td><td></td><td></td><td></td></tr><tr><td>Button</td><td></td><td></td><td></td><td></td></tr></tbody></table>

Using these components to create an accessible form may require configuring the component settings and parameters in a specific way. Ensure all labels, descriptions, and other relevant fields are completed as required.

### Avoiding incompatible components

A selection of components may present elements or functionality that do **not** comply with accessibility standards. The following components are **not** included in the Accessibility Compliance Module, and using them may create accessibility limitations in a form or application:

<table data-full-width="false"><thead><tr><th>Basic</th><th>Advanced</th><th>Layout</th><th>Data</th><th>Premium</th></tr></thead><tbody><tr><td>Select using Choices.js</td><td>Tags</td><td>Tabs</td><td>Data Map</td><td>CAPTCHA</td></tr><tr><td></td><td>Address</td><td></td><td>Data Grid</td><td>Nested Form</td></tr><tr><td></td><td>Date &#x26; Time</td><td></td><td>Edit Grid</td><td>Sketchpad</td></tr><tr><td></td><td>Survey</td><td></td><td>DataTable</td><td>Tagpad</td></tr><tr><td></td><td>Signature</td><td></td><td></td><td>Custom</td></tr></tbody></table>

### Wizards and Accessibility

Displaying a form as a Wizard, it is an accessibility best practice to ensure the [Form Settings](/form-building/form-settings) set the **Wizard Header** to *Classic.* Using a *Vertical* header/step indicator may require significant customization to meet accessibility standards.

### Using Accessible Templates

When using the USWDS template, it must be imported and registered to be used within the application, similar to the following:

```javascript
import uswds from '@formio/uswds';
import { Formio } from '@formio/js';
Formio.use(uswds);
```

The USWDS template does not require the Accessibility Module. Likewise, the Accessibility Module does not necessitate using the USWDS template for all forms.\
Some features, however, require the use of **both** the Accessibility Module **and** the USWDS template. Such features include:

* Accessible tooltip&#x73;*.*
* Accessible Date/Time component.
* Ability to use accessible “Modal Edit” windows for components when being filled in by end users.

In order to use USWDS templates within FormView Pro or Form Manager, the Enterprise Server in the deployment must have the [environment variable](/deploy/enterprise-server#environment-variables) `VPAT=true` .

## **Embedding Accessible Forms**

Accessible forms are used just like any other form, with the additional steps of importing the necessary module and any required templates.

To embed the `“https://forms.mysite.com/myproject/myform` directly to a website the following code would be used:

```html
<html>
    <head>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uswds/3.1.0/css/uswds.min.css">
        <link rel="stylesheet" href="https://cdn.form.io/js/formio.form.min.css">
        <link rel="stylesheet" href="https://cdn.form.io/uswds/uswds.min.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/uswds/3.1.0/js/uswds.min.js"></script>
        <script src="https://cdn.form.io/js/formio.form.min.js"></script>
        <script src="https://cdn.form.io/uswds/uswds.min.js"></script>
        <script src="dist/vpat.js"></script>
    </head>
    <body>
        <div id="formio"></div>
        <script type="text/javascript">
            Formio.use(vpat);
            Formio.use(uswds);
            Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform');
        </script>
    </body>
</html>
```


# Developer License

A local deployment license for the Form.io platform used for development and testing purposes.

## What is a Developer License?

The Form.io Developer License enables developers to spin up and down instances of the Form.io platform locally on the developer's machine allowing for local development and testing without affecting the remotely deployed platform configuration.

The local deployments must be connected to a local database. The developer license allows for local deployments of projects, stages, forms, and API/PDF servers.

‌The developer license is priced on a per-seat basis. Customers with a subscription for a remotely deployed configuration containing 3 or more API Server Environments are eligible to order a Developer License.

{% hint style="info" %}
Contact <sales@form.io> for more information on the Developer License
{% endhint %}

## Developer License Script

With a developer license, servers can be locally deployed and connected to a single local MongoDB. Please note you will not be able to use the "replicaSet" option for the connection or connect to any remote databases. All connections must be to a local database.

```
docker network create formio || true && \
mkdir ~/opt/mongodb || true && \
docker run -itd  \
  --name formio-mongo \
  --network formio \
  --volume ~/opt/mongodb:/data/db \
  --restart unless-stopped \
  mongo && \
docker run -d \
  -e "LICENSE_KEY=YOURLICENSE" \
  -e "MONGO=mongodb://localhost:27017/formio" \
  -e "PORTAL_ENABLED=true" \
  -e "ADMIN_EMAIL=admin@example.com" \
  -e "ADMIN_PASS=CHANGEME" \
  -e "DB_SECRET=CHANGEME" \
  -e "JWT_SECRET=CHANGEME" \
  -e "PDF_SERVER=http://pdf-server:4005" \
  --restart unless-stopped \
  --link pdf-server:pdf-server \
  --network formio \
  --name formio-server \
  -p 3000:80 \
  formio/formio-enterprise && \
mkdir ~/seaweedfs/data || true && \
mkdir ~/seaweedfs/config || true && \
docker run -itd \
  -e "AWS_ACCESS_KEY_ID=CHANGEME" \
  -e "AWS_SECRET_ACCESS_KEY=CHANGEME" \
  --network formio \
  --name formio-seaweedfs \
  --restart unless-stopped \
  -p 8333:8333 \
  -v ~/seaweedfs/data:/data \
  server -s3 && \
docker run -itd \
  -e "LICENSE_KEY=YOURLICENSE" \
  -e "MONGO=mongodb://mongo:27017/formio" \
  -e "FORMIO_S3_SERVER=seaweedfs" \
  -e "FORMIO_S3_PORT=8333" \
  -e "FORMIO_S3_BUCKET=formio" \
  -e "FORMIO_S3_KEY=CHANGEME" \
  -e "FORMIO_S3_SECRET=CHANGEME" \
  --network formio \
  --link formio-mongo:mongo \
  --link formio-seaweedfs:seaweedfs\
  --restart unless-stopped \
  --name pdf-server \
  -p 4005:4005 \
  formio/pdf-server;

```


# JavaScript Development


# JavaScript Frameworks

A list of all the Progressive Web Application frameworks supported by the Form.io platform.

## JavaScript

At its core, the Form.io platform uses a plain JavaScript (aka Vanilla JavaScript) renderer to render the forms within an application. This renderer, as well as all documentation, can be found on Github @ [**https://github.com/formio/formio.js**](https://github.com/formio/formio.js). For the full documentation, please take a look at [**Form Renderer Documentation**](/dev/form-development/form-renderer) in the help guides.

This renderer is able to easily render a form using the following code within your application either via Script embedding or application embedding.

### Script Embedding

This allows the embedding of a form directly within an HTML application using the script tags within the header. The scripts and CSS that need to be included are as follows.

{% hint style="info" %}
Navigate to the following link for more information about the [**Form.io CDNs**](https://help.form.io/dev/javascript-development/spaces/dE1To8ypyE1yhXEJ7QlD/pages/2ae5hrS2IA25reIexyXB#what-are-the-form.io-cdns)
{% endhint %}

<pre class="language-html"><code class="lang-html"><strong>&#x3C;html>
</strong><strong>  &#x3C;head>
</strong>    &#x3C;meta charset="utf-8">
    &#x3C;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
    &#x3C;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
    &#x3C;script src="https://cdn.form.io/js/formio.embed.js">&#x3C;/script>
  &#x3C;/head>
  &#x3C;body>
    &#x3C;div id='formio'>&#x3C;/div>
    &#x3C;script type='text/javascript'>
      Formio.createForm(
        document.getElementById('formio'), 
        'https://forms.mysite.com/myproject/myform'
      );
    &#x3C;/script>
  &#x3C;/body>
&#x3C;/html>
</code></pre>

The **Form Builder** can also be embedded using the following code.

<pre class="language-html"><code class="lang-html">&#x3C;html>
  &#x3C;head>
    &#x3C;meta charset="utf-8">
<strong>    &#x3C;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
</strong><strong>    &#x3C;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
</strong>    &#x3C;link rel="stylesheet" href="https://cdn.form.io/js/formio.full.min.css">
    &#x3C;script src="https://cdn.form.io/js/formio.full.min.js">&#x3C;/script>
  &#x3C;/head>
  &#x3C;body>
<strong>    &#x3C;div id="builder">&#x3C;/div>
</strong>    &#x3C;script type="text/javascript">
      Formio.builder(document.getElementById('builder'), {}, {});
    &#x3C;/script>
  &#x3C;/body>
&#x3C;/html>
</code></pre>

### Application Embedding

The form renderer can also be embedded within an application by first including the formiojs renderer as an NPM dependency and then using the following code.

```bash
npm install @formio/js
```

```javascript
import { Formio } from '@formio/js';
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform');
```

And the following CSS should also be included in your application SASS file.

```javascript
@import '@formio/js/dist/formio.form.min.css';
```

For more documentation on the JavaScript renderer, please check out the following links.

* [Form.io Github Page](https://github.com/formio/formio.js)
* [Wiki Documentation](https://github.com/formio/formio.js/wiki)
* [Examples and Additional Documentation](https://formio.github.io/formio.js/)

## Angular

The [**Angular**](https://angular.io/) framework is a very popular PWA framework offered by Google. The Form.io integration libraries provide a simple wrapper around the JavaScript renderer library but expose a number of helper components and modules that enable rapid application development within the Angular framework.

### Angular Versions

This library supports many different Angular Versions. If you wish to use this library with your specific version of Angular, then you will need to install the following versions.

| @formio/angular | Angular Version | formiojs\* |
| --------------- | --------------- | ---------- |
| 6.0.0           | 16              | 4.x        |
| 6.5.0           | 16              | 5.x        |
| 7.0.0           | 17              | 4.x        |
| 7.5.0           | 17              | 5.x        |
| 8.0.0           | 18              | 5.x        |
| 9.0.0           | 19              | 5.x        |
| 10.0.0          | 20              | 5.x        |
| 11.0.0-fjs4     | 20, 21, 22      | 4.x        |
| 11.0.0          | 20, 21, 22      | 5.x        |

*\*Note: The formiojs namespace changes from formiojs (4.x) to @formio/js (5.x)*

### Angular Renderer

{% embed url="<https://github.com/formio/angular>" %}

To use this within your application, you will start by importing the dependencies via NPM.

```bash
npm install --save @formio/js @formio/angular
```

Once the library is imported into your Angular application, you can render a form using the following code.

```javascript
import { FormioModule } from '@formio/angular';
@NgModule({
    imports: [
        ...,
        FormioModule
    ],
    ...
})
export class AppModule { }
```

And then the following can be used within your templates to render a form.

```javascript
<formio src='https://forms.mysite.com/myproject/myform'></formio>
```

There are many other modules and helper components within the Angular library, so we recommend checking out the list of other documentation and examples at the following links.

### Angular Demo Application

{% embed url="<https://github.com/formio/angular-demo>" %}

### Angular Other Resources

* [**Angular Library Github Homepage**](https://github.com/formio/angular)
* [**Wiki Documentation**](https://github.com/formio/angular/wiki)
* [**Example/Starter Application**](https://formio.github.io/angular-demo/#/)
* [**Starter Application Source Code**](https://github.com/formio/angular-demo)
* [**Walkthrough Video (using Angular 5)**](https://www.youtube.com/watch?v=zEvzW_sSXk0)

## React

React is a popular JavaScript library for building PWA applications. It is maintained by Facebook. The Form.io integration libraries provide a simple wrapper around the JavaScript renderer library but expose a number of helper components and modules that enable rapid application development within React.

### React Versions <a href="#react-versions" id="react-versions"></a>

This library supports many different React Versions. If you wish to use this library with your specific version of React, then you will need to install the following versions.

| @formio/react | React Version | formiojs\* |
| ------------- | ------------- | ---------- |
| 5.2.x         | 17            | 4.x        |
| 5.3.x         | 18            | 5.x        |
| 6.0.x         | 18            | 4.x        |
| 6.1.x         | 19            | 5.x        |
| 6.2.x         | 19            | 5.x        |

*\*Note: The formiojs namespace changes from formiojs (4.x) to @formio/js (5.x)*

### React Renderer

{% embed url="<https://github.com/formio/react>" %}

To use this within your application, you will start by importing the dependencies via NPM.

```bash
npm install --save @formio/js @formio/react
```

Once the library is imported into your React application, you can render a form using the following code.

```javascript
import { createRoot } from 'react-dom/client';
import { useEffect, useState } from 'react';
import {
	useFormioContext,
	FormioProvider,
	FormType,
	Form,
} from '@formio/react';

const FormsByUser = ({ userId }: { userId: string }) => {
	const { Formio, projectUrl } = useFormioContext();
	const [forms, setForms] = useState<FormType[]>([]);
	useEffect(() => {
		const fetchForms = async () => {
			const formio = new Formio(projectUrl);
			try {
				const forms = await formio.loadForms({
					params: { type: 'form', owner: userId },
				});
				setForms(forms);
			} catch (err) {
				console.log(
					`Error while loading forms for user ${userId}:`,
					err,
				);
			}
		};
		fetchForms();
	}, [Formio, projectUrl, userId]);
	return forms.map(function (form) {
		return (
			<>
				<Form src={form} />
				<div style={{ marginBottom: '10px' }} />
			</>
		);
	});
};

const domNode = document.getElementById('root');
const root = createRoot(domNode);
const root = createRoot();
root.render(
	<FormioProvider projectUrl="https://examples.form.io">
		<App />
	</FormioProvider>,
);
```

There are many other modules and helper components within the React library, so we recommend checking out the list of other documentation and examples at the following links.

### React Starter Application

{% embed url="<https://github.com/formio/react-app-starterkit>" %}

### React Components vs Form.io Components

React and Form.io both use the word "components" to refer to discreet modules of reusable code, but they are distinctly different and the difference must be understood.

In React, components are UI building blocks that render elements on the page, while in Form.io, components are data-driven form elements that power dynamic forms, workflows, and APIs. Form.io components are not just the data field UI, they define data structures, validation, and API interactions, to create a fully integrated form and data management system.

### React Wrapper

Form.io provides a React wrapper that makes embedding forms in a React application completely seamless. Developers should not try to import custom React components directly into Form.io forms. Instead, use the React wrapper to integrate the rendered forms seamlessly alongside any other React component. This allows for tight integration with React’s state management, event handling, and styling, while still benefiting from the Form.io Platform's schema-driven approach.

#### Integrating forms with the React wrapper

Rather than treating the Form.io Platform as an isolated system, the React wrapper integrates a React app and the Form.io form engine.\
Forms may trigger React state updates, listen to events, and interact with other components in the app without breaking the schema-driven approach of Form.io

This ensures:

* **Separation of concerns:** Control of the broader application’s UI is handled entirely by React, while the the form’s behavior is handled entirely with the Form.io Platform.
* **Scalability:** The app remains scalable without needing to modify form components at the code level.
* **Flexibility:** The Form.io Platform's JSON-driven forms stay flexible and dynamic while still aligning with the application’s design system.

## Vue

The Form.io Vue renderer allows integration with the popular [**Vue.js framework**](https://vuejs.org/).

| @formio/vue | Vue Version | @formiojs |
| ----------- | ----------- | --------- |
| 5.x         | 3           | 4x        |
| 6.0.x       | 3           | 5.x       |
| 6.1.x       | 3           | 5.x       |
| 6.2.x       | 3           | 5.x       |

### Vue Renderer

{% embed url="<https://github.com/formio/vue>" %}

To use this within your application, you will start by importing the dependencies via NPM.

```bash
npm install --save @formio/js @formio/vue
```

Once the library is imported into your Vue application, you can render a form using the following code.

```html
<template>
  <formio :src="formUrl" @submit="onSubmitMethod" />
</template>
<script>
import { Form } from '@formio/vue';

export default {
  data: function() {
    // Load these from vuex or some other state store system.
    return {
      formUrl: "https://forms.mysite.com/myproject/myform"
    }
  },
  components: {
    formio: Form
  },
  methods: {
    onSubmitMethod: function(submission) {
      console.log(submission);
    }
  }
};
</script>
```

Form components provide many helpful properties which allow you to configure your form. Here are the most common of them.

| Property   | Description                                      | Value example                                                                              |
| ---------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| src        | An embed URL to load a form                      | [**https://forms.mysite.com/myproject/myform**](https://forms.mysite.com/myproject/myform) |
| form       | Form JSON schema, can be used instead of the src | <p>{</p><p>type: 'form',<br>display: 'form',</p><p>components: \[...],</p><p>}</p>         |
| submission | Submission to set when the form is loaded        | <p>{<br>data: {...},<br>state: 'submitted',<br>}</p>                                       |
| options    | Form options                                     | <p>{<br>readOnly: true,<br>noAlerts: false,<br>saveDraft: false,<br>}</p>                  |

There are many other modules and helper components within the Vue library, so we recommend checking out the list of other documentation and examples at the following links.

### Vue Starter Application

{% embed url="<https://github.com/formio/vue-app-starterkit>" %}


# JavaScript SDK

This page describes the Form.io JavaScript SDK

The JavaScript API is a minimalistic API library that allows you to work with the Form.io API's within your web application.

{% embed url="<https://www.loom.com/share/1de51ee80e124057943f1b1f6a3895c3>" %}

## Installation

The Form.io SDK is part of our Open Source formio.js library which is found @ [**https://github.com/formio/formio.js**](https://github.com/formio/formio.js). There are two ways to include the JavaScript SDK into your application.

### Include using script tag

You can include it in a **script** tag within your application like the following shows.

```html
<script src="https://cdn.form.io/js/formio.full.min.js"></script>
```

{% hint style="info" %}
Navigate to the following link for more information about the [**Form.io CDNs**](https://help.form.io/dev/javascript-development/spaces/dE1To8ypyE1yhXEJ7QlD/pages/2ae5hrS2IA25reIexyXB#what-are-the-form.io-cdns)
{% endhint %}

Which would would then be able to do the following within your application.

```html
<script type="text/javascript">
    // Load a form.
    var formio = new Formio('https://forms.mysite.com/myproject/myform');
    formio.loadForm().then(function(form) {
        console.log(form);
    });
</script>
```

### Import into application

You can also import the SDK into your application as follows.

First perform an `npm install` using the terminal application.

```bash
npm install --save @formio/js
```

Then, you can import it into your application as follows.

```javascript
import { Formio } from '@formio/js';

// Load a form
const formio = new Formio('https://forms.mysite.com/myproject/myform');
formio.loadForm().then(function(formio) {
  console.log(formio);
});
```

## Usage

Creating an instance of Formio is simple, and takes only a path (URL String). The path can be different, depending on the desired output. The Formio instance can also access higher level operations, depending on how granular of a path you start with.

```javascript
const formio = new Formio(<endpoint>, [options]);
```

Where ***endpoint*** is any valid API endpoint within Form.io. These URL's can provide a number of different methods depending on the granularity of the endpoint. This allows you to use the same interface but have access to different methods depending on how granular the endpoint url is.

The ***options*** (optional) is used to configure certain behaviors of the JavaScript API. The following options are available.

| Property  | Description                                                             | Example                                                           |
| --------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------- |
| base      | Allows you to override the base api url.                                | [https://api.mysite.com](https://api.mysite.com/)                 |
| project   | Allows you to override the project api url.                             | [https://humanresources.form.io](https://humanresources.form.io/) |
| namespace | The namespace to store the localStorage variables. Defaults to *formio* | formio                                                            |

## API Scopes

When using the JavaScript SDK, it is important to understand the different kinds of API scopes that are being queried via the API. The Form.io API is hierarchical which is also congruent with the JavaScript SDK when making API calls with the SDK. The following scopes are provided via the Form.io API / SDK (we will use "formio.com" as the hypothetical domain name you have deployed the Form.io platform against.

| Scope      | Description                                              | Example API                         |
| ---------- | -------------------------------------------------------- | ----------------------------------- |
| Root       | This is the root or base URL for your Form.io deployment | <https://forms.mysite.com>          |
| Project    | This is the API endpoint for a specific project          | :rootScope/project/:projectId       |
| Form       | This is the API endpoint for a specific                  | :projectScope/form/:formId          |
| Submission | This is the API endpoints for a specific submission      | :formScope/submission/:submissionId |
| Action     | This is the API endpoints for specific action            | :formScope/action/:actionId         |
| Role       | This is the API endpoints for a specific role.           | :projectScope/role/:roleId          |

### Project and Form Aliases

The Form.io API also uses aliases to make the use of the hierarchical API's easier to use. Currently, we provide alias support for both Projects and Forms, so that a typical Form URL would look like the following.

```
https://forms.mysite.com/myproject/myform
```

Where `forms.mysite.com` would be replaced with the URL of your deployment, `myproject` would be replaced with the alias name of your project, and `myform` would be replaced with the name of your form. All API endpoints within the examples below will use this URL format to demonstrate the different kinds of SDK methods.

There are cases where you may be referencing a form that exists within the Form.io SaaS environment (<https://portal.form.io>). These forms have the following structure.

```
https://forms.mysite.com/myproject/myform
```

This SaaS hosted form exists within the `examples` project and references the `example` form within that project.

{% hint style="info" %}
SaaS hosted forms should only be used to trial the Form.io platform. Production use of forms should be done from within your own environment.
{% endhint %}

### Examples

If you wish to load the project JSON, or search for forms, you will instantiate as follows.

```javascript
const formio = new Formio('https://forms.mysite.com/myproject');
formio.loadForms().then((forms) => {
  console.log(forms);
});
```

*If you wish to load a specific submission.*

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/submission/23234234234234');
formio.loadSubmission().then((submission) => {
  console.log(submission);
});
```

Now that we understand how the SDK works, we can see all of the different API's available to the different API scopes as follows.

## Static Methods

There are a few methods that are used statically, meaning that they do not require the `new Formio` as the other methods require. These methods can be used as globals that are able to define the behavior of the JavaScript SDK and all instances created afterward. These methods are as follows.

### `Formio.setBaseUrl(baseUrl)`

Sets the Base URL of the renderer and SDK. This is a very important method that allows you to provide to the JavaScript SDK the Base Deployment URL of your API platform. This is always going to be the root URL of your deployment, which is also the same as the URL for the deployed developer portal application (if you have that enabled). The best way to know if you have this correct is that you should see the "status" of your deployment by going to `:baseUrl/status` If this shows the version of the server, then you know this is the value of the base URL.

Example:

```javascript
Formio.setBaseUrl('https://forms.mysite.com');
```

### `Formio.setProjectUrl(projectUrl)`

This is the Project URL that will be used to reference any Project endpoints within the SDK and renderer. This is also important to establish within your application to ensure that all relative urls are referencing the correct Project endpoints.

Example:

```javascript
Formio.setProjectUrl('https://forms.mysite.com/yourproject');
```

### `Formio.fetch(...)`

This method is a simple shim around the [HTTP Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) polyfill.

### `Formio.request(url, [method], [data], [header], [opts])`

A static method to perform an API request to any REST API endpoint. This method is a simple wrapper around the JavaScript fetch method with the added handling of JWT tokens as well as implements a Caching mechanism for GET requests to ensure that multiple requests of the same nature do not constantly spam the API server. It's parameters are defined as follows.

| Parameter         | Description                                                              |
| ----------------- | ------------------------------------------------------------------------ |
| url               | The URL you wish to send the request to.                                 |
| method (optional) | The method of the request. GET, PUT, POST, DELETE                        |
| data (optional)   | The data to include for PUT and POST requests                            |
| header (optional) | An instance of the HTTP Header class to define headers for this request. |
| opts (optional)   | See [Query Options](#query-options-query)                                |

Example: Send a request to fetch submissions.

```javascript
Formio.request(
  'https://forms.mysite.com/myproject/customers/submission?data.number=1',
  'GET',
  null,
  null,
  {
    headers: {
      'content-type': 'application/json'
    },
    mode: 'cors',
  }).then(function(result) {
    console.log(result);
  });
```

### `Formio.makeStaticRequest(url, [method], [data], [opts])`

This static method performs an API call to the Form.io API platform. This method is very similar to other [request method](#formio-request-url-method-data-header-opts) but will also send the request through the Form.io fetch plugin to allow any fetch plugin to intercept the request being made. Its parameters are defined as follows.

| Parameter         | Description                                       |
| ----------------- | ------------------------------------------------- |
| url               | The URL you wish to send the request to.          |
| method (optional) | The method of the request. GET, PUT, POST, DELETE |
| data (optional)   | The data to include for PUT and POST requests     |
| opts (optional)   | See [**Query Options**](#query-options-query)     |

### `Formio.setToken(token)`

Sets or removes the JWT token within localStorage.

| Parmeter | Description                                                                                                                        |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| token    | A JWT token to set within localStorage. If the value of this parameter is empty, then the token will be deleted from localStorage. |

### `Formio.getToken()`

Retrieve the JWT token from localStorage.

### `Formio.setUser(user)`

Sets the User JSON object of the currently logged in user. This is the same JSON object that you would get if you sent an API request to `/current` with your current JWT token. This user object is then stored within localStorage as `formioUser` unless a different `namespace` option is being used.

| Parameter | Description                                                               |
| --------- | ------------------------------------------------------------------------- |
| user      | The JSON of the user object that is fetched from the `/current` endpoint. |

### `Formio.getUser()`

Fetch the user JSON object from the localStorage.

### `Formio.currentUser([formio], [opts])`

Fetch the current user via the `/current` API endpoint.

| Parameter         | Description                                   |
| ----------------- | --------------------------------------------- |
| formio (optional) | An instance of the Formio SDK if necessary.   |
| opts (optional)   | See [**Query Options**](#query-options-query) |

### `Formio.accessInfo([formio])`

Retrieves the access information for a specific project. You must ensure you set the project url using `Formio.setProjectUrl()` before calling this method.

| Parameter         | Description                                 |
| ----------------- | ------------------------------------------- |
| formio (optional) | An instance of the Formio SDK if necessary. |

### `Formio.projectRoles([formio])`

Retrieves the roles for a specific project. You must ensure you set the project url using `Formio.setProjectUrl()` before calling this method.

| Parameter         | Description                                 |
| ----------------- | ------------------------------------------- |
| formio (optional) | An instance of the Formio SDK if necessary. |

### `Formio.clearCache()`

Clears all the fetch caches to ensure that any future requests will retrieve fresh data from the API's.

### `Formio.logout([formio], [opts])`

Perform a logout against the Form.io API server.

### `Formio.pageQuery()`

Helper function to retrieve all of the URL query parameters in a javascript key-value pair mapped object.

Example: Given the following url

```
https://app.yoursite.com/#/home?data.firstName=Travis&sort=-created
```

If you run this method on that page, it will return the following.

```javascript
const pageQuery = Formio.pageQuery();
console.log(pageQuery['data.firstName']); // Prints "Travis"
console.log(pageQuery.sort); // Prints "-created"
```

### `Formio.ssoInit([type], [options])`

Initializes an SSO processes. This is used during SAML authentication processes to instantiate and continue a SAML SSO process.

#### Instantiate a SAML SSO process

Assuming that your project is configured for SAML, you can instantiate an SSO process by executing the following.

```javascript
Formio.ssoInit('saml')
```

#### Process a SAML response

Once the SAML authentication returns to the application, you can process that response using the following.

```javascript
if (Formio.pageQuery().saml) {
    const sso = Formio.ssoInit('saml');
    if (sso) {
        sso.then((user) => {
          window.location.href = '/';
        });
    }
}
```

The following parameters can be used.

| Parameter | Description                                                                                                                                                                                                                                                                                                                                                                                                                    |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| type      | The type of SAML sso authentication to instantiate. Either "saml" or "okta"                                                                                                                                                                                                                                                                                                                                                    |
| options   | <p>An object of options, which depends on the type.</p><p>For <strong>saml</strong> type:</p><p>- relay: This is the variable that will be provided to the relay of the sso process.</p><p>For <strong>okta</strong> type:</p><p>- OktaAuth: An instance of the OktaAuth javascript object provided by Okta Javascript SDK</p><p>- formio: An instance of the Form.io SDK.</p><p>- scopes: A string of CSV scopes to apply</p> |

### `Formio.requireLibrary(name, property, src, [polling])`

Require an external JavaScript library for lazy-loading purposes.

| Parameter | Description                                                                                                                                                                                                                   |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name      | The name of the library                                                                                                                                                                                                       |
| property  | The property that is added to the "window" object that indicates that the library has finished loading. For example, if you are wanting to load the "Lodash" library, the variable that is added to the window object is "\_" |
| src       | The URL of the library you wish to load.                                                                                                                                                                                      |
| polling   | Creates a polling check to see if the library has finished loading.                                                                                                                                                           |

```javascript
Formio.requireLibrary(
    'lodash',
    '_',
    'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js',
    true
).then(function() {
    console.log(_.version); // Lodash is now part of the dom.
});
```

### `Formio.libraryReady(name)`

Returns a promise that will resolve once the library of the provided name is ready to be used.

| Parameter | Description                                             |
| --------- | ------------------------------------------------------- |
| name      | The name of the library to check if it is ready or not. |

```javascript
Formio.libraryReady('lodash').then((_) => {
    // Lodash is now ready!
    console.log(_);
});
```

### `Formio.loadProjects([query], [opts])`

A static method to load all projects within the configured `baseUrl` of the SDK.

| Parameter        | Description                                   |
| ---------------- | --------------------------------------------- |
| query (optional) | See [**Query Options**](#query-options-query) |
| opts (optional)  | See [**Fetch Options**](#fetch-options-opts)  |

### `Formio.serialize(obj, [interpolate])`

A method that will serialize a data map key-value pair object into a URL query string.

| Parameter              | Description                                                                    |
| ---------------------- | ------------------------------------------------------------------------------ |
| obj                    | The object to serialize into a URL query string.                               |
| interpolate (optional) | An optional interpolation method to interpolate certain values that are added. |

## Project API Scope

The following API's are defined at the Project Scope. To instantiate the SDK at the project scope, you simply need to provide a Project API to the constructor as follows.

```javascript
const formio = new Formio('https://forms.mysite.com/myproject')
```

where "myproject" would be the alias name of your project. Once you have instantiated the SDK with the following URL, the following methods are now available to you at the Project Scope.

### `formio.loadProject([query], [opts])`

Loads the project using the following Project Load API

| Parameter        | Description                                   |
| ---------------- | --------------------------------------------- |
| query (optional) | See [**Query Options**](#query-options-query) |
| opts (optional)  | See [**Fetch Options**](#fetch-options-opts)  |

```javascript
formio.loadProject().then((project) => {
    // Prints the project JSON
    console.log(project);
});
```

### `formio.saveProject(project, [opts])`

Creates or Updates a project depending on if the \_id of the project is provided (upsert).

**Example: Create a new project**

```javascript
const formio = new Formio('https://forms.mysite.com');
formio.saveProject({
    "title": "New Project",
    "name": "proj980",
    "description": "An example application",
    "settings": {
        "cors": "*"
    }
}).then((project) => {
    // Prints the project that was saved via API.
    console.log(project);
});
```

**Example: Update an existing project.**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject');
formio.loadProject().then((project) => {
    project.title = 'Updated Title';
    formio.saveProject(project).then((updated) => {
        // Prints the updated project json.
        console.log(updated);
    });
});
```

| Parmameters     | Description                                                                                                                                                            |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| project         | The project JSON you wish to create or update. If an "\_id" is provided within the json, an update operation will be executed, otherwise it will create a new project. |
| opts (optional) | See [**Fetch Options**](#fetch-options-opts)                                                                                                                           |

### `formio.deleteProject([opts])`

Deletes a project.

```javascript
var formio = new Formio('https://forms.mysite.com/myproject');
formio.deleteProject().then(() => {
    console.log('The project has been deleted!');
});
```

| Parmameters     | Description                                  |
| --------------- | -------------------------------------------- |
| opts (optional) | See [**Fetch Options**](#fetch-options-opts) |

### `formio.loadForms([query], [opts])`

Loads all the forms within a project. This implements the [**List Forms API**](https://apidocs.form.io/#a39be766-02dd-0b95-49bd-971fcef25a32).

| Parameter        | Description                                   |
| ---------------- | --------------------------------------------- |
| query (optional) | See [**Query Options**](#query-options-query) |
| opts (optional)  | See [**Fetch Options**](#fetch-options-opts)  |

**Example: List all Resources within a project, sort them based on created date, and only return the "title" and "path" of those forms**

```javascript
formio.loadForms({
  params: {
    type: 'resource',
    select: 'title,path',
    sort: '-created'
  }
}).then((resources) => {
  console.log(resources);
});
```

Example: List all Forms within a project, limit them to 20, and only return the "title" of those forms.

```javascript
formio.loadForms({
  params: {
    type: 'form',
    select: 'title',
    limit: 20
  }
}).then((forms) => {
  console.log(forms);
});
```

### `formio.getTempToken(expire, allowed, [options])`

Retrieves a temporary auth token which can be used in conjunction with the PDF API's to download a PDF output of a submission.

```javascript
formio.getTempToken(
    3600, 
    'GET:/project/234234234234234/form/234234234234234/submission/234234234234234/download'
).then((tokens) => {
    console.log(tokens);
});
```

### `formio.loadRoles([opts])`

Loads a list of roles for the provided project. Implements the [**List Roles API**](https://apidocs.form.io/#8ecd0673-9088-4157-ae0d-161f93d090fb)

| Parameter       | Description                                  |
| --------------- | -------------------------------------------- |
| opts (optional) | See [**Fetch Options**](#fetch-options-opts) |

### `formio.getProjectId()`

Returns the Project ID of the project in context, even if the URL provided to the constructor uses the project alias.

```javascript
const formio = new Formio('https://forms.mysite.com/myproject');
formio.getProjectId().then((projectId) => {
    // Prints the project id for the "myproject" project.
    console.log(projectId);
});
```

### `formio.accessInfo()`

Retrieve the access information for a project. This method implements the [**Project Access Info API**](https://apidocs.form.io/#5c5f5b08-8602-b5dd-51ee-15ac8f7116ea)

```javascript
formio.accessInfo().then((accessInfo) => {
    // Output the role information for this project.
    console.log(accessInfo.roles);
});
```

### `formio.currentUser()`

Based on the JWT token stored within the localStorage, this method will retrieve the current user metadata and information.

```javascript
formio.currentUser().then((user) => {
    // The current user.
    console.log(user);
});
```

## Form API Scope

The following API's are available when the Form.io SDK is instantiated with the form scope like the following illustrates

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform');
```

### `formio.loadForm([query], [opts])`

Loads a form json

| Parameter        | Description                               |
| ---------------- | ----------------------------------------- |
| query (optional) | See [Query Options](#query-options-query) |
| opts (optional)  | See [Fetch Options](#fetch-options-opts)  |

### `formio.saveForm(form, [opts])`

Creates or Updates a form depending on if an "\_id" property is provided within the form json.

| Parameter       | Description                                                                                                                                                                   |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| form            | The JSON of the form to save or update. If an "\_id" is provided as a property of the form json, then an update operation is performed, otherwise, it will create a new form. |
| opts (optional) | See [Fetch Options](#fetch-options-opts)                                                                                                                                      |

**Example: Create a new form**

```javascript
// Project scope is only required for creating new forms.
const formio = new Formio('https://forms.mysite.com/myproject');

formio.saveForm({
  title: 'Registration',
  path: 'registration',
  name: 'registration',
  components: [
    {type: 'textfield', key: 'firstName', label: 'First Name'}
    {type: 'textfield', key: 'lastName', label: 'Last Name'}
  ]
}).then((form) => {
  // Prints out the saved form object.
  console.log(form);
});
```

**Example: Update an existing form**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform');
formio.loadForm().then((form) => {
  form.title = 'Updated title';
  formio.saveForm(form).then((updated) => {
    console.log(updated);
  });
});
```

### `formio.deleteForm([opts])`

Deletes a form

| Property        | Description                              |
| --------------- | ---------------------------------------- |
| opts (optional) | See [Fetch Options](#fetch-options-opts) |

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform');
formio.deleteForm().then(() => {
    console.log('Form was deleted!');
});
```

### `formio.getFormId()`

Returns the form Id of the form in context even if the form alias was provided for this form.

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform');
formio.getFormId().then((formId) => {
    // Prints the form id for "myform"
    console.log(formId);
});
```

### `formio.loadSubmissions([query], [opts])`

Loads a view of submissions for a form. This implements the [Get Submissions API](https://apidocs.form.io/#1f207caa-9d04-3e81-2973-e4bf82ee5190)

| Parameter        | Description                               |
| ---------------- | ----------------------------------------- |
| query (optional) | See [Query Options](#query-options-query) |
| opts (optional)  | See [Fetch Options](#fetch-options-opts)  |

**Example: Load first 10 submissions, sort by descending created date**

```javascript
formio.loadSubmissions({
  params: {
    sort: '-created'
  }
}).then((submissions) => {
  console.log(submissions);
});
```

**Example 2: Load first 20 submissions where the form field age is greater than 18, and sort by modified.**

```javascript
formio.loadSubmissions({
    params: {
        sorted: 'modified',
        'data.age__gt': 18,
        limit: 20
    }
}).then((submissions) => {
    console.log(submissions);
});
```

### `formio.loadActions([query], [opts])`

Loads the Actions for a given form. This implements the [List Actions API](https://apidocs.form.io/#3f2531ad-bd2e-4e8e-889f-1bce44ce9651)

| Parameter        | Description                               |
| ---------------- | ----------------------------------------- |
| query (optional) | See [Query Options](#query-options-query) |
| opts (optional)  | See [Fetch Options](#fetch-options-opts)  |

Examples will be very similar to the loadSubmissions API, but will query against the action json objects instead.

### `formio.availableActions()`

Returns a list of available actions that can be added to this form. Implements the [Available Actions API.](https://apidocs.form.io/#9515276c-a3cb-400b-b7fd-3ab6db4821f0)

### `formio.actionInfo(name)`

Returns the action information for a specific action including the settings form. This implements the [Action Info API](https://apidocs.form.io/#cb8f638d-351b-49c7-ab47-32eb55031994)

| Parameter | Description                                                       |
| --------- | ----------------------------------------------------------------- |
| name      | The name of the action you would like to retrieve information on. |

## Submission API Scope

The following API's are available when the Form.io SDK is instantiated with the submission scope like the following illustrates

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/submission/234234234234234');
```

### `formio.loadSubmission([query], [opts])`

Loads a submission for a given form.

| Parameter        | Description                               |
| ---------------- | ----------------------------------------- |
| query (optional) | See [Query Options](#query-options-query) |
| opts (optional)  | See [Fetch Options](#fetch-options-opts)  |

**Example: Load the submission**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/submission/234234234234234');
formio.loadSubmission().then((submission) => {
    console.log(submission);
});
```

### `formio.saveSubmission(submission, [opts])`

Creates or Updates a submission depending on if an "\_id" property is provided within the submission json.

| Parameter       | Description                                                                                                                                                                                     |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| submission      | The JSON of the submission to save or update. If an "\_id" is provided as a property of the submission json, then an update operation is performed, otherwise, it will create a new submission. |
| opts (optional) | See [Fetch Options](#fetch-options-opts)                                                                                                                                                        |

**Example: Create a new submission**

```javascript
// Form scope is only required for creating new submissions.
const formio = new Formio('https://forms.mysite.com/myproject/myform');

formio.saveSubmission({
  data: {
    firstName: 'Joe',
    lastName: 'Smith'
  }
}).then((submission) => {
  // Prints out the saved submission object.
  console.log(submission);
});
```

**Example: Update an existing submission**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/submission/234234234234234');
formio.loadSubmission().then((submission) => {
  submission.data.firstName = 'Updated Name';
  formio.saveSubmission(submission).then((updated) => {
    console.log(updated);
  });
});
```

### `formio.deleteSubmission([opts])`

Deletes a submission

| Property        | Description                              |
| --------------- | ---------------------------------------- |
| opts (optional) | See [Fetch Options](#fetch-options-opts) |

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/submission/234234234234234');
formio.deleteSubmission().then(() => {
    console.log('Submission was deleted!');
});
```

### `formio.getDownloadUrl([form])`

Retrieves a PDF download url for a specific form.

| Parameter | Description                                                                                                     |
| --------- | --------------------------------------------------------------------------------------------------------------- |
| form      | The form JSON to retrieve a download url from. If none is provided, then it will use the form that is in scope. |

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/submission/234234234234234');
formio.getDownloadUrl().then((url) => {
    // This will print the PDF download url, which also includes the temp token.
    console.log(url);
});
```

### `formio.uploadFile(storage, file, fileName, dir, progressCallback, url, options, fileKey, groupPermissions, groupId, uploadStartCallback, abortCallback)`

Uploads a file to the provided storage system. See [File Component ](https://github.com/formio/formio.js/blob/master/src/components/file/File.js#L724)for specific usage and implementation details.

### `formio.downloadFile(file, [options])`

Downloads a file from the provided storage system. See [File Component ](https://github.com/formio/formio.js/blob/master/src/components/file/File.js#L724)for specific usage and implementation details.

### `formio.deleteFile(file, [options])`

Deletes a file from the provided storage system. See [File Component ](https://github.com/formio/formio.js/blob/master/src/components/file/File.js#L724)for specific usage and implementation details

## Action API Scope

The following API's are available when the Form.io SDK is instantiated with the action scope like the following illustrates

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/action/234234234234234');
```

### `formio.loadAction([query], [opts])`

Loads an action for a given form.

| Parameter        | Description                               |
| ---------------- | ----------------------------------------- |
| query (optional) | See [Query Options](#query-options-query) |
| opts (optional)  | See [Fetch Options](#fetch-options-opts)  |

**Example: Load the action**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/action/234234234234234');
formio.loadAction().then((action) => {
    console.log(action);
});
```

### `formio.saveAction(action, [opts])`

Creates or Updates an action depending on if an "\_id" property is provided within the action json.

| Parameter       | Description                                                                                                                                                                         |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| action          | The JSON of the action to save or update. If an "\_id" is provided as a property of the action json, then an update operation is performed, otherwise, it will create a new action. |
| opts (optional) | See [Fetch Options](#fetch-options-opts)                                                                                                                                            |

**Example: Create a new action**

```javascript
// Form scope is only required for creating new actions.
const formio = new Formio('https://forms.mysite.com/myproject/myform');

formio.saveAction({
	"data": {
		"name": "email",
		"title": "Email",
		"method": ["create"],
		"handler": ["after"],
		"priority": 0,
		"settings": {
			"emails": ["test@example.com"],
			"from": "np-reply@form.io",
			"message": "{{ submission(data, form.components) }}",
			"subject": "New submission for {{ form.title }}.",
			"transport": "default"
		}
	}
}).then((action) => {
  // Prints out the saved action object.
  console.log(action);
});
```

**Example: Update an existing submission**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/action/234234234234234');
formio.loadAction().then((action) => {
  action.title = 'Updated Action Title';
  formio.saveAction(action).then((updated) => {
    console.log(updated);
  });
});
```

### `formio.deleteAction([opts])`

Deletes an action

| Property        | Description                              |
| --------------- | ---------------------------------------- |
| opts (optional) | See [Fetch Options](#fetch-options-opts) |

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform/action/234234234234234');
formio.deleteAction().then(() => {
    console.log('Action was deleted!');
});
```

## Role API Scope

The following API's are available when the Form.io SDK is instantiated with the role scope like the following illustrates

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/role/234234234234234');
```

### `formio.loadRole([opts])`

Loads a role json.

| Parameter       | Description                              |
| --------------- | ---------------------------------------- |
| opts (optional) | See [Fetch Options](#fetch-options-opts) |

**Example: Load the role**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/role/234234234234234');
formio.loadRole().then((role) => {
    console.log(role);
});
```

### `formio.saveRole(role, [opts])`

Creates or Updates a role depending on if an "\_id" property is provided within the role json.

| Parameter       | Description                                                                                                                                                                   |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| role            | The JSON of the role to save or update. If an "\_id" is provided as a property of the role json, then an update operation is performed, otherwise, it will create a new role. |
| opts (optional) | See [Fetch Options](#fetch-options-opts)                                                                                                                                      |

**Example: Create a new role**

```javascript
// Project scope is only required for creating new roles.
const formio = new Formio('https://forms.mysite.com/myproject');

formio.saveRole({
	title: 'Employee',
  description: 'A person who belongs to a company.'
}).then((role) => {
  // Prints out the saved role object.
  console.log(role);
});
```

**Example: Update an existing role**

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/role/234234234234234');
formio.loadRole().then((role) => {
  role.title = 'Manager';
  formio.saveRole(role).then((updated) => {
    console.log(updated);
  });
});
```

### `formio.deleteRole([opts])`

Deletes a role

| Property        | Description                              |
| --------------- | ---------------------------------------- |
| opts (optional) | See [Fetch Options](#fetch-options-opts) |

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/role/234234234234234');
formio.deleteRole().then(() => {
    console.log('Role was deleted!');
});
```

## Utility Methods

### `formio.isObjectId(id)`

Determines if the provided "id" is a valid MongoDB ObjectId

### `formio.userPermissions([user], [form], [submission])`

Fetches an object that describes the users permissions as it pertains to the provided user, form, and submission. If any of these are not provided, then the current object in context is used.

### `formio.canSubmit()`

Returns a promise if the user can submit the form in scope.

```javascript
const formio = new Formio('https://forms.mysite.com/myproject/myform');
formio.canSubmit().then((canSubmit) => {
    if (canSubmit) {
        console.log('The user can submit the form!');
    }
    else {
        console.log('The user cannot submit the form!');
    }
});
```

## Fetch Plugin API

Formio.js can register plugins that can hook into request calls in several ways. Every fetch plugin is defined using the following JSON structure.

```javascript
const FetchPlugin = {
    /**
     * The priority of the plugin relative to other plugins that determines call 
     * order. Higher numbers have higher priority. If not specified it will 
     * default to a priority of 0.
     */
    priority: 0,
    
    /**
     * An initialization function called when registered with Formio.
     *
     * @param Formio - The static class of the Form.io SDK
     */
    init: (Formio) => {
    
    },
    
    /**
     * A deregistration function called when deregistering with Formio
     *
     * @param Formio - The static class of the Form.io SDK
     */
    deregister: (Formio) => {
    
    }
};

Formio.registerPlugin(FetchPlugin, 'customfetch');
```

### **`Formio.registerPlugin(plugin, [name])`**

Registers a fetch plugin with the Form.io SDK.

| Parameter       | Description                                                      |
| --------------- | ---------------------------------------------------------------- |
| plugin          | An instance of the Fetch plugin as described above.              |
| name (optional) | The name of this plugin so that it can be retrieved easily later |

### **`Formio.getPlugin(name)`**

Returns the plugin registered with the given name.

```javascript
const plugin = Formio.getPlugin('customplugin');
```

### **`Formio.deregisterPlugin(plugin)`**

Deregisters a plugin with Form.io SDK. It will call the `deregister` function on the plugin before deregistering. The `plugin` argument can be the instance of the plugin or the optional name given when registered. Returns true if the plugin was successfully deregistered, false if the plugin does not exist.

### Plugin hooks

Plugins can provide hooks that are invoked at different points in the library. To use a particular hook below, add a function to your plugin with the same name as the hook.

The following are the currently available hooks.

#### **`preRequest(requestArgs)`**

Called before a request. If you return a promise, Formio.js will wait for it to resolve before starting the request.

`requestArgs` is an object that contains the following properties:

* `formio`: The Formio instance calling the request.
* `type`: The type of resource being requested (ex: form, forms, submission).
* `url`: The url being requested.
* `method`: The HTTP request method.
* `data`: The HTTP request body, if any.
* `opts`: Any opts given to the request

#### **`request(requestArgs)`**

Called before a request, and gives plugins a chance fulfill the request before it is sent. If you return a non-null, non-undefined value (or a promise that resolves to one), that will be used as the results of the request instead of making the default network request.

Only the first highest priority that returns a value will replace the contents. Your plugin's hook will not be called if a higher priority plugin returns a value.

`requestArgs` is an object that contains the following properties:

* `formio`: The Formio instance calling the request.
* `type`: The type of resource being requested (ex: form, forms, submission).
* `url`: The url being requested.
* `method`: The HTTP request method.
* `data`: The HTTP request body, if any.
* `opts`: Any opts given to the request

#### **`wrapRequestPromise(promise, requestArgs)`**

Called when a request is made and gives plugins access to the promise that is returned when a user makes a request. The promise that is returned from this hook will be returned to the user. You may wrap the original promise or extend the promise chain with this hook. (You must return a promise that uses the original promise, or the promise returned to users will not resolve as expected).

`promise` is the promise of the request.

`requestArgs` is an object that contains the following properties:

* `formio`: The Formio instance calling the request.
* `type`: The type of resource being requested (ex: form, forms, submission).
* `url`: The url being requested.
* `method`: The HTTP request method.
* `data`: The HTTP request body, if any.
* `opts`: Any opts given to the request

#### **`preStaticRequest(requestArgs)`**

Same as `preRequest` hook but used for requests that use the global Formio object instead of a Formio instance. This includes functions like `Formio.loadProjects()`, `Formio.availableActions()`, `Formio.currentUser()`.

`requestArgs` is an object that contains the following properties:

* `url`: The url being requested.
* `method`: The HTTP request method.
* `data`: The HTTP request body, if any.

#### **`staticRequest(requestArgs)`**

Same as `request` hook but used for requests that use the global Formio object instead of a Formio instance. This includes functions like `Formio.loadProjects()`, `Formio.availableActions()`, `Formio.currentUser()`.

`requestArgs` is an object that contains the following properties:

* `url`: The url being requested.
* `method`: The HTTP request method.
* `data`: The HTTP request body, if any.

#### **`wrapStaticRequestPromise(promise, requestArgs)`**

Same as `wrapRequestPromise` hook but used for requests that use the global Formio object instead of a Formio instance. This includes functions like `Formio.loadProjects()`, `Formio.availableActions()`, `Formio.currentUser()`.

`promise` is the promise of the request.

`requestArgs` is an object that contains the following properties:

* `url`: The url being requested.
* `method`: The HTTP request method.
* `data`: The HTTP request body, if any.

#### Example Plugin

This example plugin will delay all requests by 5 seconds

```javascript
var DelayPlugin = {
  priority: 0,
  preRequest: function(requestArgs) {
    return new Promise(function(resolve, reject){
      setTimeout(resolve, 5000);
    })
  },
  request: function(args) {
    console.log('Request has been made!', args);
    
    // You can alter the response by changing null to the response you wish to make.
    return Promise.resolve(null);
  }
}

Formio.registerPlugin(DelayPlugin, 'delay');
```

## Query Options (query)

Many of the GET API calls made in this SDK include a variable called **query**. This is a variable that allows you to pass along query parameters within the URLs that will be used as the API endpoints. The following are properties that can be utilized within the **query** parameter.

{% hint style="info" %}
The Formio SDK methods primarily abstract HTTP requests to various Form.io APIs. To determine valid query parameters, refer to the [**Form.io API documentation**](https://apidocs.form.io/). Identifying the specific API you’re using will clarify which query parameters are needed to optimize your requests
{% endhint %}

| Property | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| params   | <p>An object key-value pair that will be added to the URL as query parameters for the API call.</p><p><strong>Example:</strong> Load all forms, but filter them by resources and sort them by created descending.</p><p><code>var formio = new Formio('<https://form.io/myproject>');</code><br><code>formio.loadForms({</code></p><p><code>params: {</code><br><code>type: 'resource',</code><br><code>sort: '-created'</code><br><code>}</code></p><p><code>});</code></p><p>The following will produce the following API url.</p><p><code><https://forms.mysite.com/myproject/form?type=resource&#x26;sort=-created></code></p> |

## Fetch Options (opts)

All of the API calls made within this SDK contain a parameter that we will call **opts.** This is a variable that allows you to pass special options to the fetch methods for the API call being made. The following are properties that can be utilized within the **opts** parameter.

| Property    | Description                                                                                                                                                                                                                                                                                                                                       |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| header      | An instance of the Headers class to define the headers of the request                                                                                                                                                                                                                                                                             |
| headers     | <p>A JavaScript object key-value map of the headers you would like to introduce.</p><p>Example:</p><p><code>formio.loadSubmissions({}, {</code></p><p><code>headers: {</code><br><code>'custom-header': 'Testing'</code><br><code>}</code></p><p><code>});</code></p>                                                                             |
| formio      | A custom instance of the Form.io SDK to use for this request.                                                                                                                                                                                                                                                                                     |
| ignoreCache | <p>Boolean (true) to tell the request to ignore any memory cache of the request. This is useful if you make a request that changes something and then wish to GET additional data without using the cached response.</p><p>Example:</p><p><code>formio.loadSubmission({}, {</code></p><p><code>ignoreCache: true</code></p><p><code>})</code></p> |
| noToken     | Boolean (true) to tell the API call to not include the Form.io JWT token along with the request.                                                                                                                                                                                                                                                  |
| namespace   | The namespace to use as a prefix of all variables being saved into localStorage for this request. For example, setting this to "test" will save the JWT token into the "testToken" variable instead of the default "formioToken"                                                                                                                  |


# JavaScript Utilities

This section documents the utilities functions available within the JavaScript SDK

## Introduction

The Form.io Utilities class is a part of the JavaScript SDK, but provides a number of methods that makes working with Form.io forms within your applications easier.

## Installation

To install the Utilities, you can either import them directly into your application as follows.

```javascript
import { Utils } from '@formio/js/utils';
```

or they can be used as part of the Form.io renderer by including the following script in your application.

```html
<script src="https://cdn.form.io/js/formio.form.min.js"></script>
```

{% hint style="info" %}
Navigate to the following link for more information about the [**Form.io CDNs**](https://help.form.io/dev/javascript-development/spaces/dE1To8ypyE1yhXEJ7QlD/pages/2ae5hrS2IA25reIexyXB#what-are-the-form.io-cdns)
{% endhint %}

and then you can find the Utilities methods as part of the `Utils` property on the `Formio` object.

```javascript
Formio.Utils.eachComponent(....)
```

## Utility Functions

The following are common functions that can be used within the Form.io Utilities library.

### `eachComponent(components, fn, [includeAll])`

Calls `fn(component)` for each component in `components`, accounting for nested layout components. (Does not call for layout components themselves, unless includeAll is true).

| Parameter  | Description                                                                          |
| ---------- | ------------------------------------------------------------------------------------ |
| components | An array of JSON form components to iterate over.                                    |
| fn         | The function to call for each input component.                                       |
| includeAll | Boolean to indicate if we should include all components including layout components. |

The current data path of the element. Example: data.user.firstName

```javascript
import { Utils } from '@formio/js/utils';
Utils.eachComponent(form.components, function(component) {
  // Do something...
})
```

### `getComponent(components, key)`

Returns the component with the given `key` or undefined if not found.

| Parameter  | Description                                          |
| ---------- | ---------------------------------------------------- |
| components | An array of JSON form components to iterate over.    |
| key        | The key of the component you would like to retrieve. |

<pre class="language-javascript"><code class="lang-javascript"><strong>import { Utils } from '@formio/js/utils';
</strong>var component = Utils.getComponent(form.components, 'myKey');
</code></pre>

### `findComponents(components, query)`

Returns an array of components that match the find query criteria. This query is very similar to MongoDB where if you wish to find a nested query, you would provide the key as the path of the property using dot notation.

| Parameter  | Description                                                                |
| ---------- | -------------------------------------------------------------------------- |
| components | An array of JSON form components to iterate over.                          |
| query      | A JSON object to use as a query to find a certain component within a form. |

Here is an example.

```javascript
// Find all textfields with a specific custom property.
import { Utils } from '@formio/js/utils';
var comps = Utils.findComponents(form.components, {
  'type': 'textfield',
  'properties.objectId': '2345'
});

// Should return all textfield components with 'properties.objectId' = '2345'.
console.log(comps);
```

### `searchComponents(components, query)`

Finds a component provided a query of properties of that component.

| Parameter  | Description                                       |
| ---------- | ------------------------------------------------- |
| components | An array of JSON form components to iterate over. |
| query      | The query to pass to `matchComponent`.            |

### `matchComponent(component, query)`

Matches if a component matches the query.

| Parameter | Description                                               |
| --------- | --------------------------------------------------------- |
| component | A component JSON you would like to match against a query. |
| query     | A JSON query to use as the match query.                   |

```
const component = {
    type: 'textfield',
    key: 'firstName',
    label: 'First Name'
};
if (utils.matchComponent(component, {
    key: 'firstName
}) {
    console.log('The component matches!!');
}
```

###

### `flattenComponents(components, includeAll)`

Returns a key-value object where the keys are the keys for each component in `components` and each key points to the corresponding component. This includes nested components as well. Pass true for includeAll if you want to include layout components.

| Parameter  | Description                                                                            |
| ---------- | -------------------------------------------------------------------------------------- |
| components | An array of JSON form components to iterate over.                                      |
| includeAll | Boolean to indicate if you wish to include all components including layout components. |

```javascript
import { Utils } from '@formio/js/utils';
var flattened = Utils.flattenComponents(form.components);
console.log(flattened['myNestedComponent']);
```

### `isLayoutComponent(component)`

Determine if a component is a layout component.

| Parameter | Description                                                   |
| --------- | ------------------------------------------------------------- |
| component | The component JSON to determine if this is a layout component |

```javascript
import { Utils } from '@formio/js/utils';
var layoutComponent = Utils.isLayoutComponent(form.components[0]);
console.log(layoutComponent);
```

### `getValue(submission, key)`

Get the value for a components API key, from the given submission. Recursively searches the submission for the key.

| Parameter  | Description                                                                     |
| ---------- | ------------------------------------------------------------------------------- |
| submission | The submission JSON object                                                      |
| key        | The component key you would like to fetch the value from within the submission. |

```javascript
import { Utils } from '@formio/js/utils';
var value = Utils.getValue(submission, 'myComponent'); // The value or undefined.
```

### `parseFloat(value)`

Extension of standard [**parseFloat**](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) function, that also clears input string. Useful for [**Currency component**](https://help.form.io/form-building/components/#currency).

| Parameter | Description                        |
| --------- | ---------------------------------- |
| value     | The value you would like to parse. |

```javascript
Utils.parseFloat('12,345,678.90'); // -> 12345678.90
```

### `formatAsCurrency(value)`

Formats provided value in way how [**Currency component**](https://help.form.io/form-building/components/#currency) uses it.

| Parameter | Description                         |
| --------- | ----------------------------------- |
| value     | The value you would like to format. |

```javascript
Utils.formatAsCurrency(123.4); // -> '123.40'
Utils.formatAsCurrency(12345678.9); // -> '12,345,678.90'
Utils.formatAsCurrency(12345678.915); // -> '12,345,678.92'
Utils.formatAsCurrency('12345678.915'); // -> '12,345,678.92'
```

### `escapeRegExCharacters(value)`

Escapes RegEx characters in provided String value.

| Parameter | Description                                                   |
| --------- | ------------------------------------------------------------- |
| value     | The value you would like to escape the regex characters from. |

```javascript
Utils.escapeRegExCharacters('[form.io](https://form.io/)'); // -> '\[form\.io\]\(https:\/\/form\.io\)'
```

### `boolValue(value)`

Determines the boolean value of a setting.

### `isMongoId(text)`

Check to see if an ID is a mongoID.

### `checkCondition(component, row, data, form, instance)`

Checks the conditions for a provided component and data.

| Parameter | Description                                                |
| --------- | ---------------------------------------------------------- |
| component | The component JSON                                         |
| row       | Contextual row data                                        |
| data      | Full submission data                                       |
| form      | The form JSON schema                                       |
| instance  | The component instance this method is being executed with. |

### `unescapeHTML(str)`

Unescape HTML characters like <, >, & and etc.

### `convertStringToHTMLElement(str, selector)`

Make HTML element from string

### `guid()`

Generate a GUID

### `isValidDate(date)`

Checks a date to see if it is valid.

### `formatDate(value, format, timezone, flatPickrInputFormat)`

Format a date provided a value, format, and timezone object.

### `getBrowserInfo()`

Get the browser name and version

### `isInputComponent(componentJson)`

Checks to see if a component JSON is an input component.


# JavaScript Evaluator

### JavaScript Evaluation

Within the renderer and builder code, it is possible write custom snippets of JavaScript to perform custom actions that would otherwise be difficult to configure though standard configuration.\
These snippets of JavaScript are introduced through Form Builder interface, through options like Custom Default Value, Calculated Values, Logic, as well as many others.

These snippets are viewed and edited through a special JavasSript editor within the Form Builder. The editor provides a review of the variables available within the execution context, as seen here:

<figure><img src="/files/P2szjLyLG2Dp6upE0K8K" alt=""><figcaption><p>JavaScript evaluation within the form builder.</p></figcaption></figure>

### Evaluation Context

For every JavaScript evaluation that occurs, there are a number of variables that are presented within the execution sandbox. These variables are commonly referred to as the **evalContext** variables. Some of the evaluations provide their own evalContext (which are documented separately), however the following eval variables tare common across all evaluation types:

| Variable      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Example                                                                                                                                                                                                                                                                                                    |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| form          | The complete [**Form JSON**](/form-building/form-json) schema of the form.                                                                                                                                                                                                                                                                                                                                                                                                                  | <p><code>{</code></p><p><code>"\_id": "....",</code></p><p><code>"path": "user",</code></p><p><code>"name": "user",</code></p><p><code>"display": "form",</code></p><p><code>"components": \[</code></p><p><code>{</code></p><p><code>...</code><br><code>}</code><br><code>]</code><br><code>}</code></p> |
| submission    | The complete [**Submission JSON** ](/form-building/submissions)of the current submission for the rendered form.                                                                                                                                                                                                                                                                                                                                                                             | <p><code>{</code><br><code>"data": {</code><br><code>"first": "Joe",</code><br><code>"last": "Smith"</code><br><code>},</code><br><code>"metadata": {}</code><br><code>}</code></p>                                                                                                                        |
| component     | The current Component JSON schema.                                                                                                                                                                                                                                                                                                                                                                                                                                                          | <p><code>{</code><br><code>"type": "textfield",</code><br><code>"label": "Name",</code><br><code>"key": "name"</code><br><code>}</code></p>                                                                                                                                                                |
| value         | The current component value.                                                                                                                                                                                                                                                                                                                                                                                                                                                                | `show = value === 5;`                                                                                                                                                                                                                                                                                      |
| instance      | <p>This points to the component instance. This is helpful if you wish to gain access to the actual component instance object to perform special functions and execute certain methods of the component.<br><br>Go to <a href="https://github.com/formio/formio.js/blob/master/src/components/_classes/component/Component.js"><strong><https://github.com/formio/formio.js/blob/master/src/components/_classes/component/Component.js></strong></a> to see what methods you can access.</p> | `valid = instance.checkValidity()`                                                                                                                                                                                                                                                                         |
| self          | Alias of "instance"                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                                                                                                                                                                                                                                                                                            |
| instance.root | This always points to the form instance that contains the component. This is helpful if you wish to reference other components using the following code.                                                                                                                                                                                                                                                                                                                                    | `instance.root.getComponent('email') = 'joe@example.com';`                                                                                                                                                                                                                                                 |
| options       | The [**Form Renderer Options**](/dev/form-renderer) passed to the renderer.                                                                                                                                                                                                                                                                                                                                                                                                                 | <p><code>{</code><br><code>"i18n": {</code><br><code>"language": "es",</code><br><code>"es": {</code><br><code>...</code><br><code>}</code><br><code>}</code><br><code>}</code></p>                                                                                                                        |
| data          | The root data context for the renderer. This will always point to the full data object from "submission.data"                                                                                                                                                                                                                                                                                                                                                                               | <p><code>{</code><br><code>"first": "Joe",</code><br><code>"last": "Smith",</code><br><code>"children": \[</code><br><code>{</code><br><code>"first": "...",</code><br><code>"last": "..."</code><br><code>}</code><br><code>]</code><br><code>}</code></p>                                                |
| row           | The "row" variable is a special "context" data object that points to the current data "context" of the component. This changes based on what component we are referring to. For example, if you are within a DataGrid component (which is an array of objects), the "row" will point to the current row object.                                                                                                                                                                             | <p>Let's suppose you have a DataGrid called Children, and you wish to write javascript to validate the birthday component within the children DataGrid. You would be able to use "row" to point to the "current" row's birthday field like the following.<br><br><code>row\.birthday</code></p>            |
| rowIndex      | This is the index for the current row you are on. For DataGrid and EditGrid components, this is a number where 0 means we are on the first row, 1 means we are on the second row, etc.                                                                                                                                                                                                                                                                                                      | <p>0 - first row</p><p>1 - second row</p><p>...</p>                                                                                                                                                                                                                                                        |
| t             | A function, which is used to translate certain strings using the [**Translation**](/dev/translations) system.                                                                                                                                                                                                                                                                                                                                                                               | `value = t('First Name');`                                                                                                                                                                                                                                                                                 |
| \_            | An instance of Lodash which can be used to simplify certain operations within your javascript code.                                                                                                                                                                                                                                                                                                                                                                                         | `value = _.get(data, 'a.b')`                                                                                                                                                                                                                                                                               |
| utils         | An instance of the [**Form Utilities**](/dev/javascript-utilities).                                                                                                                                                                                                                                                                                                                                                                                                                         | <p><code>utils.eachComponent(component.components, function(component) {</code><br><code>...</code><br><code>});</code></p>                                                                                                                                                                                |
| util          | Alias of "utils"                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |                                                                                                                                                                                                                                                                                                            |
| user          | The currently authenticated User object.                                                                                                                                                                                                                                                                                                                                                                                                                                                    | `value = user.data.email;`                                                                                                                                                                                                                                                                                 |
| token         | The current JWT token for the authenticated user.                                                                                                                                                                                                                                                                                                                                                                                                                                           |                                                                                                                                                                                                                                                                                                            |
| moment        | An instance of the [**Moment.js**](https://momentjs.com/) library.                                                                                                                                                                                                                                                                                                                                                                                                                          | `valid = moment.diff(value, '12/5/2021') > 0;`                                                                                                                                                                                                                                                             |
| config        | The current [**Public Configuration**](https://help.form.io/admin/projects#public-configuration) config that has been added to the form json.                                                                                                                                                                                                                                                                                                                                               |                                                                                                                                                                                                                                                                                                            |

#### Custom Evaluation Context Variables

In addition to having the standard variables as shown above, it is possible to also introduce your own evaluation context variables that can be used within the evaluations. This is very helpful in case you have pre-defined methods for validations, etc. that you would like to expose to all of the evaluations. This can be achieved using either the Form Module found in your Project Settings, or through the embedding of the form.

**Form Module Example**

Within your Project Settings, click on Settings > **Custom JS and CSS.** Within this section, you will see a section called **Form Module** which is used to write a snippet of JSON that is able to dynamically configure the form as it is being embedded within an application. You can introduce a new context variable as follows.

```
{
  options: {
    form: {
      evalContext: {
        validatePhone: function(input) {
          return input.match(/^[2-9]\d{2}-\d{3}-\d{4}$/);
        }
      }
    }
  }
}

```

With this example, there would now be a new method available in the evaluation context called "validatePhone" and could be used as follows within a Custom Validation block.

```
valid = validatePhone(input) ? true : 'Phone number is invalid';
```

**Form Embedding Example**

You can also set custom evaluation context variables when you embed the form. The following shows an example of how this could be done.

```
Formio.createForm(document.getElementById('formio'), 'https://forms.mysite.com/myproject/myform', {
  evalContext: {
    validatePhone: function(input) {
      return input.match(/^[2-9]\d{2}-\d{3}-\d{4}$/);
    }
  }
})
```

This can then be used in the same way as described above.

Now that we have an understanding of evaluation contexts, let's discuss all the different places where javascript evaluations can be performed. There are many sections that allow for JavaScript evaluation. These sections are described as follows.

### Custom Default Value

This provides a way to set the custom default value of the component you are currently configuring. The default value is the value that is used at the initialization of the component and provides you an opportunity to set the initial value of the component, but also provides a good point to place any initialization code you may wish to add to the component.

**Additional Evaluation Context**

For custom default values, there are a few additional evaluation context variables that are used.

| Variable | Description                                   | Example      |
| -------- | --------------------------------------------- | ------------ |
| value    | The value to set as the custom default value. | `value = 5;` |

**Example 1: Set custom default value to the combination of other fields.**

```
value = data.firstName + " " + data.lastName;
```

**Example 2: Listen for change events of this component and set the value of another component**

```
instance.on('change', function(event) {
  if (
    event && 
    event.changed && 
    event.changed.component && 
    event.changed.component.key === component.key) 
  {
    instance.root.getComponent('email') = instance.getValue() + '@example.com';
  }
});
```

### Calculated Value

The calculated value snippet allows you to write custom pieces of javascript that set the value of a component. The value is set by setting the variable "value" within the snippet of javascript.

**Additional Evaluation Context**

For calculated values, there are a few additional evaluation context variables that are used.

| Variable | Description                               | Example      |
| -------- | ----------------------------------------- | ------------ |
| value    | The value to set as the calculated value. | `value = 5;` |

**Example 1: Perform a Total Amount calculation on values in a data grid**

Assuming that there is a Data Grid component called "Scores" that contains a component within the data grid called "Score", you could have a component outside of the data grid, called "Total" with the following calculated value.

```
value = data.scores.reduce(function(total, row) {
  return total + row.score;
}, 0);
```

**Example 2: Conditionally calculate a value**

You can also choose to set the value within an if statement, and this would only set the value under certain conditions. For example, this could be used to force a "maximum" value.

```
if (instance.getValue() > 10) {
  value = 10;
}
```

### Custom Validation

Custom Validations allow you to write a snippet of JavaScript that decides how the component should be validated as well as what error to show when the evaluation is determined to be invalid. This can be achieved using the following additional context variables exposed to the custom validation section.

**Additional Evaluation Context**

For calculated values, there are a few additional evaluation context variables that are used.

| Variable | Description                                                                                                                                                                                                                              | Example                                                |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| input    | The value that has been input into the component that is being compared for evaluation.                                                                                                                                                  | `valid = input === 5;`                                 |
| valid    | A special variable that determines if the component is valid. If the value is set to "true", then the component is valid. Otherwise you would set the value of "valid" to the string you would like to show the user when it is invalid. | `valid = input === 5 ? true : 'The value must be 5!';` |

**Example 1: Validate that this "validate password" field matches the "password" field.**

```
valid = input === data.password ? true : 'Passwords must match!';
```

### Advanced Conditions

Advanced conditions allow you to write a snippet of Javascript that determines the visibility/validation condition for the component. When the value of a conditional is set to false, the component effectively becomes "inactive" which means it is both not included visibly in the form, but also is not evaluated for validity. This is commonly used to present different sections of the form based on the answers provided by other fields.

**Additional Evaluation Context**

For advanced conditions, there are a few additional evaluation context variables that are used.

| Variable | Description                                                                                                                                                                                                                                                                       | Example                       |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| show     | Determines if this component is visible or not. If show is equal to "false", then the component not only becomes invisible, but also is no longer evaluated for validity. For example, if the field is required, but is conditionally not visible, then it no longer is required. | `show = value === 'Testing';` |
| value    | The current value of the component that is being compared for evaluation.                                                                                                                                                                                                         | show = value === 5;           |

### Logic: JavaScript Trigger

Within the Logic tab, there is an ability to add Logic to your forms to perform different operations such as hiding the component, making it required, etc under certain conditions. The triggers for logic determine how the current logic section is triggered.

**Additional Evaluation Context**

For calculated values, there are a few additional evaluation context variables that are used.

| Variable | Description                                                                                                                                     | Example                                    |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| result   | Determines if the logic section should be triggered. If result is set to "true" it will be triggered, if it is set to "false", then it will not | `result = data.email === 'admin@form.io';` |

**Example 1: Trigger the logic if the average grades are less than 70**

```
var total = data.grades.reduce((total, grade) => total + grade, 0);
var average = total / data.grades.length;
result = average < 70.0;
```

### Logic: Custom Actions

Within the Logic, after a logic section has been triggered, it will now perform the "action" of that logic. This is the "do something" part of the logic section where it performs an operation. Within this section, it is possible to write your own javascript to perform the action you would like to perform within the action.

**Example 1: Set the component value when the value executes.**

```
value = data.score1 + data.score2;
```

## JSON Logic

Within every evaluation type, there is also the ability to configure the evaluations using JSON schemas. This is helpful if you wish to perform complex evaluations without the requirement of executing the JavaScript "eval" necessary to perform the javascript evaluations of the scripts shown above.

{% hint style="info" %}
There are other options for not using "eval" such as using the protected eval plugin described below, but JSON Logic also serves as a good strategy for such protections.
{% endhint %}

The JSON Logic system uses the [**JSON Logic Library**](https://jsonlogic.com/) to perform the evaluations needed for each of the evaluation sections. Below are some examples of the different evaluation types on how this system can be used to create complex evaluations without using any JavaScript.

#### Custom Default Value

**Example 1: Concatenate the value of two different components string values together.**

```json
{"cat": [{"var": "data.firstName"}, " ", {"var": "data.lastName"}]}
```

#### Calculated Value

**Example 1: Sum together a multiple value number component**

```json
{"_sum": {var: "data.multinumber"}}
```

#### Custom Validation

For custom validations, you need to always use the "if" parameter within JSON Logic. The first argument to the "if" statement is the "true" case, and the second should be the error that you show when the value is not set. The following shows examples of how this is used.

**Example 1: Validate if a string is equal to a value.**

```json
{
  "if": [
    {
      "===": [
        {
          "var": "input"
        },
        "Bob"
      ]
    },
    true,
    "Your name must be 'Bob'!"
  ]
}
```

**Example 1: Validate if an email is from a certain domain**

```json
{
  "if": [
    {
      "in": [
        {
          "var": "input"
        },
        "form.io"
      ]
    },
    true,
    "The email must be from 'form.io'!"
  ]
}
```

## JavaScript Evaluator

While the Form.io platform offers a large amount of flexibility with the evaluations and executions of scripts within the renderer, it also includes even more flexibility and extensibility through the use and modification of the **Evaluator** within the renderer.

The Evaluator is a static class object where all javascript executions pass through to be evaluated. The code for the basic Evaluator class can be found at the following code.

{% embed url="<https://github.com/formio/formio.js/blob/master/src/utils/Evaluator.js>" %}
The Form.io Evaluator class
{% endembed %}

This class is used to perform any executions and 'eval' processes within the renderer from template rendering to the execution of javascript snippets within the renderer. The instance can also be referenced within your application by simply accessing the following property on the global Formio object.

```
Formio.Evaluator
```

Using this instance, you can easily configure how the Evaluator behaves such as the following describes.

### Configuring the Evaluator

There are many ways that you can use the instance of the Evaluator to modify how it behaves by default. Some of these ways are described below:

#### Turn off evaluations

The first thing you may wish to do is completely disable all evaluations from occurring. You would want to do this if you are running the renderer within a tight security environment where you may not trust the form builders who created the form, and worry about the execution of malicious JavaScript within your application. This can be done by setting the **noeval** property to true like so.

```javascript
Formio.Evaluator.noeval = true;
Formio.createForm(document.getElementById('formio'), ...);
```

#### Changing the template evaluation settings

The evaluator is also used to evaluate all templates and perform interpolations, such as the following.

```
Your first name: {{ data.firstName }}
```

This string may be contained within an HTML Element component within the form, but since it contains a token, it will be interpolated using the **evalContext** as described in the section above. It is possible to change the format of all of these templates to use a different syntax. For example, if you wish to change it to the following.

```
Your first name: <% data.firstName %>
```

you could use the templateSettings property of the Evaluator to accomplish this goal.

```javascript
Formio.Evaluator.templateSettings = {
  evaluate: /\{%([\s\S]+?)%\}/g,
  interpolate: /\<\%([\s\S]+?)\%\>/g,
  escape: /\{\{\{([\s\S]+?)\}\}\}/g
};
```

These settings are described as follows.

* **evaluate**: This is the template for string "evaluations" where it executes the javascript within. This requires that you have evaluations turned on by ensuring the "noeval" flag is not set or set to false.
* **interpolate**: This is where you can provide "interpolated" replacement values based on the values provided by the evalContext. For example `{{ data.email }}` will replace that token with the value from "data" with the key of "email"
* **escape**: This configuration tells the interpolation how to find "escaped" tokens. For example, if you wish to actually display `{{ data.email }}` and do not wish for it to be interpolated, then you will use the following string. `\{\{ data.email \}\}`

### Overriding the Evaluator

In addition to providing configurations for the Evaluator, it is also possible to perform overrides to inject your own custom code into how evaluations are performed. This can be done by injecting your own methods into the Evaluator that "inject" your own code into a method.

As a quick example of something that could be done, let's suppose you wish to `console.log` all evaluations that were being performed within the renderer, the following code could be used to "inject" this into the renderer evaluation execution.

```javascript
var evaluate = Formio.Evaluator.evaluate;
Formio.Evaluator.evaluate = function(func, args) {
  console.log(func, ...args);
  return evaluate(func, args);
}
```

This method shows how you can save off the original function as a variable, then override the method, and then use that original saved function as the function you return with the evaluation. This allows you to inject your own console.log into the process so that you can understand all evaluations that are being executed.

The following methods can be overridden:

* **`evaluator(func, ...params)`** - Returns a method of evaluation. By default, this returns a new function that will be evaluated at a later time.
* **`template(template, hash)`** - Converts a string into a template function that will be executed later.
* **`interpolate(rawTemplate, data, _options)`** - Accepts a string template, along with data context variables, and returns the interpolated result string.
* **`evaluate(func, args)`** - Executes the evaluator function (above) with the arguments provided.

#### Example: Override Evaluator to work with Node.js VM2

A very good example of how to override the Evaluator can actually be found within our Open Source server code which overrides the evaluator to perform all javascript evaluations within a VM on the server to protect against malicious code. This code in complete form can be found @ [**https://github.com/formio/formio/blob/master/src/util/util.js#L56**](https://github.com/formio/formio/blob/master/src/util/util.js#L56)

Here is a snippet that shows how the evaluator can integrate with VM2.

<pre class="language-javascript"><code class="lang-javascript">const {VM} = require('vm2');
const vm = new VM({
  timeout: 250,
  sandbox: {
    result: null,
  },
  fixAsync: true
});

<strong>Formio.Evaluator.noeval = true;
</strong>Formio.Evaluator.evaluator = function(func, args) {
  return function() {
    let result = null;
    /* eslint-disable no-empty */
    try {
      vm.freeze(args, 'args');

      result = vm.run(`result = (function({${_.keys(args).join(',')}}) {${func}})(args);`);
    }
    catch (err) {}
    /* eslint-enable no-empty */
    return result;
  };
};
</code></pre>

This code does a couple of things.

1. It turns off any normal evaluations by setting "noeval" to true.
2. It creates a new VM to perform any javascript executions within.
3. It overrides the "evaluator" method to execute the script within a VM and return the result. It also ensures that the ONLY variables that the script has access to within the VM are those provided by the evalContext.

### Custom Evaluators

In addition to overriding the base Evaluator, the renderer also enables the ability to create your own Evaluator class and register it as the new evaluator for the renderer, this documentation shows you how this can be done.

#### Building your own custom evaluator

Very similar to overriding the methods described above, it is possible to completely write your own Evaluator class, and then register that Evaluator as part of the renderer. In order to accomplish this, you will need to provide implementation to a few methods that are called from the renderer, which is defined below.

```javascript
const CustomEvaluator = {
  /**
   * Takes a string function and returns an evaluator that will perform the execution.
   *
   * @param func - This is the string representation of the function that will be executed.
   * @param params - A spread of parameters that are being passed to the function to be executed.
   *
   * @return - This function should return a method that will then be passed to the "evaluate" method of this class. 
   */
  evaluator(func, ...params) {
  },
  
  /**
   * Takes a template string, and then returns a template function that will be executed later with evalContext variables.
   *
   * @param template - A string of the template that needs to be turned into a template function.
   *
   * @return - The template function that will be executed in the future with the evalContext variables.
   */
  template(template) {
  },
  
  /**
   * A method that takes a string, and some data, and then returns the interpolated result of that string.
   *
   * @param rawTemplate - The string version of the template that should be interpolated.
   * @param data - The data that will be passed to the interplation.
   * @param options - Configuration options to use when interplating.
   *
   * @return - A string that has been interpolated. 
   */
  interpolate(rawTemplate, data, options) {
  },
  
  /**
   * Perform an evaluation
   *
   * @param func - The function that was returned by the "evaluator" method.
   * @param args - The function arguments to be passed to the evaluation function.
   *
   * @return - The result of the execution.
   */
  evaluate(func, args) {
  }
};
```

Once you have implemented your own Evaluator class, you can then register this class using the `registerEvaluator` method as follows.

```javascript
Formio.Evaluator.registerEvaluator(CustomEvaluator);
```

It is also possible to create a Form.io module, and include your custom evaluator within the export of your module as follows.

```javascript
export default {
    evaluator: CustomEvaluator
}
```

Then, someone can implement your evaluator by simply using the module as follows.

```javascript
import { Formio } from '@formio/js';
import EvaluatorModule from 'yourevaluator';
Formio.use(EvaluatorModule);
```

#### Protected Evaluator

This library can be installed and used as follows.

```
npm install --save @formio/protected-eval
```

```javascript
import ProtectedEval from '@formio/protected-eval';
import { Formio } from '@formio/js';
Formio.use(ProtectedEval);
```

There are some differences in using this evaluator that need to be understood, so please read more information about this evaluator by going to the following Github repo.

{% embed url="<https://github.com/formio/protected-eval>" %}


# Protected Evaluator

The **Protected Evaluator** is a custom evaluator offered by Form.io to protect against the execution of unsafe, user-supplied code.

The Protected Evaluator is available for use on the Form.io Github: [**https://github.com/formio/protected-eval**](https://github.com/formio/protected-eval)

The Protected Evaluator is based on the open source [JS Interpreter module.](https://github.com/NeilFraser/JS-Interpreter)

### Why use the Protected Evaluator?

Since many Form.io components can be customized with JavaScript written by Form Builders, application owners may want to evaluate such code in a protected environment by using the Protected Evaluator.

The Evaluator is a static class object that all JavaScript executions pass through to be evaluated, and thus offers a degree of protection against malicious code in component customization.

#### What customizations might require the Protected Evaluator?

Some of the customizations that may require a form to use the Protected Evaluator are:

* Conditional logic
* Calculated fields
* Custom validation
* Custom default values

These customizations often use code introduced by the Form Builder. Security practices may require the use of Protected Eval when such customizations are used.

### How to use the Protected Evaluator

To use the Protected Evaluator:

1. Install the module by using the following command:

```
npm install --save @formio/protected-eval
```

2. Import the Protected Evaluator into the application by adding the following code:

```javascript
import ProtectedEval from '@formio/protected-eval';
import { Formio } from '@formio/js';
Formio.use(ProtectedEval);
```

### Operational Impact

Protected Evaluation executes the user-supplied JavaScript on a line-by-line basis in a sandboxed environment. This necessarily introduces a degree of overhead that can affect the performance of a form. This overhead will scale linearly with the amount of custom code. As a result, forms that make significant use of calculated values, custom default values, conditional logic, etc. may see a noticeable degradation in performance.

#### Mitigating effect on performance

Every particular use case may need to find a unique balance between security and performance. In cases where performance cannot be sacrificed, some design patterns may be useful when mitigating the impact on performance:

* **Custom evaluator -** The Protected Evaluator takes a blanket approach to sandbox all custom JavaScript. If there are specific concerns that can be addressed with a more targeted evaluator, Form.io makes it easy to develop and integrate a custom evaluator.
* **Offloading logic** - In some cases, the customization done in the Form.io component can be offloaded to other aspects of the application. This reduces the need to invoke the Protected Evaluator as frequently.




---

[Next Page](/llms-full.txt/1)

