# OneClick Interface Builder > Interface Builder lets an admin build the Interface views that an Interface button opens in Pipedrive. --- # Interface Builder Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder.md Interface Builder builds the views that an Interface button opens in OneClick. - [Tutorials](/docs/buttons/interface-button/interface-builder/tutorials/01-first-interface): Step-by-step guides to build your first interface. - How-to guides: Practical recipes for common tasks. Start with [Button](/docs/buttons/interface-button/interface-builder/how-to/blocks/button). - Reference: Complete reference for all block types, data binding, and styles. Start with [Block types](/docs/buttons/interface-button/interface-builder/reference/block-types/alert). - [Explanation](/docs/buttons/interface-button/interface-builder/explanation/what-is-interface-builder): Conceptual background on the architecture, forms, and visibility systems. --- # Building Your First Interface Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/tutorials/01-first-interface.md ## Opening the Application Interface Builder is accessed from Pipedrive via a OneClick button. When the app loads, you land on the **Interface Selection Page**, which lists all views belonging to this button. You will see two tabs at the top: **Views** and **Variables**. Interface Selection Page when no views exist yet. The Views tab is selected at the top alongside a Variables tab. The 'Fortnox Invoicing / Interface Views' heading is followed by a yellow Beta Feature notice. The 'Your Views (0)' section shows an empty state with a 'No views yet' message, the helper text 'Create your first interface view to get started building custom interfaces.', and a Create New button. ## Creating a New Interface 1. On the Interface Selection Page, click the **Create New** button next to the **Your Views** heading. 2. The **Create new view** dialog opens. 3. Enter a descriptive **Name** — this name is how you will reference it later when setting up navigation between views. The optional **Description** and **Default view** toggle can be left at their defaults. 4. Click **Create**. The new view opens in the Builder. Create new view dialog overlaid on an empty Views list. The dialog contains a focused Name input, an empty Description input, a Default view toggle, and a Create button at the bottom. ## Understanding the Builder When you open a view, the Builder loads with three main areas: - **Canvas** (left side) — the main working area where you build your interface by arranging rows and blocks. - **Sidebar** (right side) — shows configuration options for whatever is selected. It has two main tabs at the top: the current selection tab (Block Settings, Row Settings, etc.) and **View settings**. - **Top Bar** — a navigation bar at the top of the canvas with the interface name, a back arrow to return to the view list, and three buttons on the right: **Preview**, **Test**, and **Sample data**. The top bar also shows a **Saving...** spinner indicator whenever your changes are being auto-saved. Empty Builder view. The top bar shows the view name 'docs-first-interface' on the left, a back arrow, and Preview, Test, and Sample data buttons on the right. The canvas in the center shows a 'Start building' placeholder with an 'Add first row' button. The right sidebar shows the View settings tab with View URL, Global Styles, and View ID fields. ## Adding a Row Before you can place any content blocks, you need a row. Rows define the column layout of your interface. 1. On an empty canvas, click the **Add first row** button. On a non-empty canvas, hover the gap between two rows and click the `+` button that appears. 2. The **Add row** dialog opens. 3. Pick a layout: - **Full width** — a single column at 100% width - **Two columns** — two equal 50/50 columns - **Three columns** — three equal 33/33/33 columns - **Sidebar left** — 25/75 split - **Sidebar right** — 75/25 split - **Form** — adds a Form Start + Form End marker pair (covered in [Building a Form](/docs/buttons/interface-button/interface-builder/tutorials/03-building-a-form)) 4. The dialog closes and the new row appears on the canvas as an empty container with a grey column placeholder. Add row dialog open over the empty canvas. The dialog lists six layout options stacked vertically with icons and short descriptions: Full width, Two columns, Three columns, Sidebar left, Sidebar right, and Form. ## Adding a Title Block 1. Click an empty column inside the row you just created. The **Add block** dialog opens. 2. Pick **Title** from the list. 3. The block appears on the canvas with an empty text value. Add block dialog open over the canvas with the empty Column on the left. The dialog grid lists Button, Title, Paragraph, Image, Divider, Table, HTML, Input (disabled), Navbar, Avatar, Hover Card, Chart, Alert, and Badge. The Title tile is highlighted with a hover state. ## Editing Block Content 1. Click on the Title block in the canvas to select it. 2. The sidebar switches to the **Block Settings** tab. 3. You will see a **Text** field. This is a Data-Picker-enabled input that supports both static text and dynamic data placeholders. 4. Type your title text, for example: `Welcome to My Interface`. 5. The canvas updates in real-time to reflect your changes. Builder canvas with a Full row containing a selected Title block. The right sidebar shows the Block Settings tab with the Configuration sub-tab open. Block Configuration fields are visible: Name 'Title' and Text 'Welcome to My Interface'. ## Adding a Paragraph Block 1. Add another row using the `+` button (or use a multi-column row from before). 2. Click an empty column to open **Add block** and pick **Paragraph**. 3. Click the new Paragraph block to select it. 4. In the **Block Settings** tab you will see a **Value** field — the same Data-Picker-enabled input as the Title block's **Text** field. 5. Type your paragraph text, for example: `This is my first interface built with Interface Builder.` Builder canvas with two Full rows. Row 1 contains a Title block; Row 2 contains a Paragraph block which is currently selected (blue outline). The right sidebar shows the Paragraph block's Block Configuration with Name 'Paragraph' and the Value field filled with 'This is my first interface built with Interface Builder.' ## Previewing Your Interface 1. Click the **Preview** button in the top bar. 2. The view switches from the Builder to Preview mode. 3. In Preview mode, you see your interface rendered as it will appear to end users. Click the **Pipedrive resource** button at the top to pick a specific deal, person, or organization to test with. 4. To return to the Builder, click the back arrow at the top-left of the Preview screen. Preview mode header (back arrow, 'Preview' title, 'Deal #1995' context badge) above the rendered interface. The interface shows the heading 'Welcome to My Interface' and the paragraph 'This is my first interface built with Interface Builder.' ## Saving Your work is saved automatically. After a brief pause in editing, the Builder saves your latest changes to the server. You will see a **Saving...** indicator with a spinner in the top bar while the save is in progress. There is no manual save button — just keep building and your changes are persisted. ## Summary In this tutorial you learned to: - Open Interface Builder from the Interface Selection Page - Create a new view via the **Create New** button and the **Create new view** dialog - Understand the Builder layout: canvas, sidebar, and top bar - Add rows from the **Add row** dialog and pick column layouts - Add Title and Paragraph blocks from the **Add block** dialog - Edit block content via the sidebar - Preview your interface - Rely on auto-save for persisting your work --- # Displaying Pipedrive Data in Your Interface Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/tutorials/02-data-binding-basics.md ## What is Data Binding? Interfaces display data from Pipedrive resources -- deals, persons, organizations, and more. Instead of typing fixed text, you bind a block's text input to a field through the **Data Picker**, and the field's current value is rendered at run time. The Data Picker inserts each field as a small **blue tag** into the editor. The compiled syntax behind the tag is `{{resource.field}}` (for example `{{deal.title}}`), but in the builder you do not type that syntax yourself -- you click the tag you want and the editor renders it as a tag. ## Opening the Data Picker 1. Select a block on the canvas (for example, a Title or Paragraph block). 2. In the Block Settings panel, find a **Data Picker-enabled input**: Title's **Text** field, Paragraph's **Value** field, and similar fields on other blocks. 3. Click inside the input. A **Data Picker tooltip** appears next to the field. 4. The tooltip's top bar contains an icon-only row of tabs: - **Deal** -- deal fields (title, value, currency, owner, ...) - **Organization** -- organization fields (name, address, ...) - **Person** -- person fields (name, email, phone, ...) - **User** -- the current logged-in user - **Custom** -- the JSON payload returned by your view's API endpoint or your saved Sample data - **Search Params** -- URL parameters passed in from another view - **Variable** -- interface-level variables you define in the Variables tab - **Functions** -- built-in helper functions Title block selected on the canvas, Text field clicked in the Block Configuration sidebar, and the Data Picker tooltip open beneath it. The top row shows the eight icon-only tabs (Deal selected); below is a search field and a list of deal fields including ID, Title, Creator, Value, Contact person, Organisation, Stage, Currency, Add time, Update time, Status, and Probability. ## Browsing Available Data 1. Click a tab to see the fields for that resource. 2. Simple fields (such as `title` or `value`) can be clicked directly to insert them as a tag. 3. Nested fields are expandable. For example, the deal's owner is an object -- expand it to pick `owner_id.name`. 4. The Data Picker remembers which tab you last opened. ## Binding a Deal Title to a Title Block 1. Add a **Title** block to your canvas (or select an existing one). 2. In Block Settings, click the **Text** field. The Data Picker opens. 3. Select the **Deal** tab. 4. Click on **Title**. 5. A blue **Title** tag is inserted into the Text field. The compiled value is `{{deal.title}}`, but you don't see the curly-brace syntax -- you see the tag. Title block on the canvas with the sidebar showing Block Configuration: Name 'Title' and a Text field that contains a single blue Data Picker tag labelled 'Title'. No curly-brace syntax is visible in the editor. ## Combining Static Text and Dynamic Data You can mix typed text with multiple tags in a single field. 1. Add a **Paragraph** block and select it. 2. In the **Value** field, type: `Deal: ` 3. Open the Data Picker and insert the deal **Title** tag. 4. Insert the deal **Currency** tag right after it (or with a space between them). The editor now shows: `Deal:` followed by a Title tag and a Currency tag. The compiled output is `Deal: {{deal.title}} {{deal.currency}}`. This technique works in any Data Picker-enabled field across all block types. Paragraph block on the canvas with the sidebar showing Block Configuration: the Value field starts with the static text 'Deal:' followed by two blue Data Picker tags ('Title' and 'Currency') from the deal tab. ## Testing with Real Data 1. Click **Preview** in the top bar to switch to Preview mode. 2. In the Preview top bar, next to the **Preview** title, there is a **Pipedrive resource** button labelled with the active resource (for example `Deal #1995`). Click it to open the **Pipedrive resource** dialog and pick a different deal, person, or organization from your account. 3. The system fetches the real data for the selected resource and replaces every Data Picker tag with the actual value. 4. Your Title and Paragraph blocks render with live Pipedrive data. If a tag references a resource that is not present (for example a person tag when no person is linked), the rendered value may be empty. Preview mode top bar shows the Preview heading and a 'Deal #1995' resource button. Below it the Title block renders as 'Legendary 1995' and the Paragraph block renders as 'Deal: Legendary 1995 EUR' -- the Title and Currency tags resolved against the live deal. ## Understanding Data Types The Data Picker organises fields by data type: - **String** -- text values such as names, titles, emails. - **Number** -- numeric values such as deal amounts and phone numbers. - **Object** -- nested structures (for example `deal.owner_id` containing `name`, `email`, ...). Expand the object to pick a sub-field; the resulting tag follows the path. - **Array** -- lists of items (for example deal products). Arrays are used by blocks that iterate, such as the Table block (covered in a later tutorial). When you pick a sub-field of an object, the Data Picker creates a tag that renders the dotted path (for example `owner_id.name`). ## Summary In this tutorial you learned to: - Bind block fields by inserting Data Picker tags instead of typing placeholder syntax - Browse the eight Data Picker tabs (Deal, Organization, Person, User, Custom, Search Params, Variable, Functions) - Mix static text and multiple tags in a single field - Preview your interface with a chosen Pipedrive resource via the Preview top-bar dialog - Work with nested object fields by expanding them in the Data Picker --- # Building a Form Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/tutorials/03-building-a-form.md ## How Forms Are Structured A form in Interface Builder is defined by two marker rows on the canvas -- **Form Start** at the top and **Form End** at the bottom -- with your content rows in between. Every input placed between those markers belongs to the form. A **Submit button** links to the form by its **Form Identifier** and is what users click to send their answers. The screenshot below shows the finished tutorial form on the canvas: Form Start carries the `contact-form` identifier badge, and the Submit button shows the same `contact-form` badge — that match is how the button knows which form to send. Builder canvas showing the completed contact-form. Form Start (Row 1) is selected and carries a 'contact-form' badge next to the row label. Row 2 holds a Full Name input with type Text. Row 3 holds an Email Address input with type Email and a small red asterisk marking it Required. Row 4 holds a Submit button with two badges — 'Submit' and 'contact-form'. Row 5 is Form End. The right sidebar shows Form Settings with Form Identifier 'contact-form' and four padding inputs all at 0 px. ## Step 1: Add a Form Element 1. Hover the canvas (or the gap between two rows) to reveal a small `+` button. 2. Click `+` to open the **Add row** dialog. 3. Pick **Form** from the layout list. Two marker rows appear on the canvas: **Form Start** on top and **Form End** at the bottom, with empty space between them. Add row dialog open on top of the empty canvas. Six layout options are listed vertically — Full width, Two columns, Three columns, Sidebar left, Sidebar right, and Form. The Form option is at the bottom and is highlighted with a hover state, with the description 'Form container for input fields'. ## Step 2: Give the Form an Identifier 1. Click the **Form Start** row (Form End works too). 2. The sidebar switches to **Form Settings**. 3. In the **Form Identifier** field, enter a descriptive name. For this tutorial, use `contact-form`. The identifier shows up as a badge on Form Start on the canvas, and it is how the Submit button (added later) will find the correct form. Form Settings tab open in the right sidebar with the Form Identifier field set to 'contact-form'. Padding Top, Bottom, Left, and Right inputs sit below at 0 px. On the canvas, the Form Start row now shows 'contact-form' as a badge next to the row label. ## Step 3: Add a Full-Name Input 1. Hover the area between Form Start and Form End — a `+` button appears. 2. Click `+`, pick a one-column **Full** layout in the **Add row** dialog. 3. Click the empty column inside that new row to open the **Add block** dialog and pick **Input**. 4. Click the new Input block to open its settings. You will see fields for **Label**, **Type**, **Placeholder**, **Help text**, **Default Value**, **Required**, and **Disabled**. 5. Set **Label** to `Full Name`. 6. Leave **Type** as **Text**. Block Configuration sidebar for an Input block. Name 'Input', Label 'Full Name', Type 'Text'. Placeholder, Help text, Pattern, and Default Value fields are empty below. Required and Disabled toggles at the bottom are off. The canvas on the left shows the new Input row inside the contact-form, with the 'Missing submit button' warning visible above it. ## Step 4: Add an Email Input 1. Repeat the same steps to add another row inside the form. 2. Add a second Input block in the new column. 3. Set **Label** to `Email Address`. 4. Change **Type** to **Email**. 5. Turn on the **Required** switch. Builder canvas with the contact-form holding two input rows between Form Start and Form End. Row 2 is a Text input labeled 'Full Name'; Row 3 is an Email input labeled 'Email Address' (currently selected, with Required toggled on in the sidebar). The 'Missing submit button' warning sits between Form Start and the input rows. ## Step 5: Add a Selection Input (Optional) If you want a drop-down or multi-choice field, pick one of these selection types for **Type**: **Single Select**, **Multi Select**, **Checkbox**, or **Radio**. An **Options Type** selector then appears with two choices: - **Static** -- you define label/value pairs manually. Use the options editor that appears to add each pair. - **Dynamic** -- options come from data at render time using the Data Picker. Enter Data Picker expressions for **Labels** and **Values**. ## Step 6: Add Pattern Validation (Optional) For the simple input types (Text, Email, Number, URL, Date) you can add regex validation: 1. In the input settings, scroll to the **Pattern** field and enter a regex (for example, `^[A-Za-z ]+$`). 2. Optionally fill **Pattern Error** with a custom message shown when the pattern fails. Test your regex at [regex101.com](https://regex101.com/) before pasting it in. ## Step 7: Add a Submit Button 1. Add a new row using the `+` button. It can be inside or outside the form boundaries — both work. 2. Click an empty column in the new row, then pick **Button** in the **Add block** dialog. 3. Click the new Button to open its settings. Set **Button Type** to **Form Submit Button**. 4. A **Form** dropdown appears. Pick `contact-form` from the list. Block Configuration sidebar for the new Button block. Button Type is set to 'Form Submit Button' and the Form dropdown shows 'contact-form'. Below them, Form Type 'JSON', an empty Submit URL (highlighted in red because it has no value yet), After submission 'Wait for response', and Timeout '10' s are visible. The canvas on the left shows the full form: Form Start (contact-form), Full Name input, Email Address input, Button row, Form End. ## Step 8: Configure Submission Once Button Type is Form Submit Button, extra settings appear. You will set **Form Type**, **Submit URL**, and an **After submission** behavior. ### Form Type - **JSON** (default) -- posts form values as a JSON payload to the Submit URL. - **Multipart/Form-Data** -- use this whenever any input has **Type = File**. - **Open view with form data** -- instead of posting anywhere, navigates to another view and passes input values as URL search parameters. ### Submit URL For **JSON** and **Multipart/Form-Data**, enter the endpoint in **Submit URL**. Opening the URL input reveals an advanced dialog where you can also add: - **Headers** -- custom HTTP headers (key/value pairs; values support the Data Picker). - **Query parameters** -- additional query string pairs. ### After submission Pick one of: - **Wait for response** -- waits up to **Timeout (s)** seconds (10--60) for the server to reply. You can turn on **Disable form after submission** (prevents double-submits) and **Show message after submission** (displays the server's confirmation). - **Select view** -- immediately navigates to a chosen **View ID** after sending. You can pass static parameters, and optionally forward every input value as search parameters to the target view. Submit button settings scrolled down to show advanced submission configuration. Form Type 'JSON', a red 'Submit URL' button (empty), After submission 'Wait for response', Timeout '10' s, Form State toggle 'Disable form after submission', User Feedback toggle 'Show message after submission', and Validation Behavior toggles ('Show error indicator on submit button', 'Scroll to first error field', 'Show error toast on submit'). ## Step 9: Add a Reset Button (Optional) To let users clear the form: 1. Add another Button block (use the `+` button to add a row, then **Add block** → **Button**). 2. Set **Button Type** to **Form Reset Button**. 3. In the **Form** dropdown, pick `contact-form`. ## Step 10: Test the Form 1. Click **Preview** in the top bar. The form renders with live inputs. 2. Fill in the fields and click the submit button to see the behavior you configured. 3. For an end-to-end test, click **Test** in the top bar -- test mode runs the interface closer to production. Preview mode header with a back arrow, 'Preview' title, and a 'Deal #1995' context badge. Below it, the contact-form is rendered with two filled fields — Full Name 'Sarah Johnson' and Email Address 'sarah.johnson@example.com' — and a blue submit Button at the bottom right of the form. ## Summary In this tutorial you learned how to: - Pick **Form** in the **Add row** dialog and work with the **Form Start** / **Form End** markers on the canvas - Set a **Form Identifier** to name the form - Add **Input** blocks with different **Types** (Text, Email, and selection types) - Configure selection inputs with **Options Type** (Static or Dynamic) - Add **Pattern** validation with a custom **Pattern Error** message - Add a **Form Submit Button** and link it to the form - Configure **Form Type**, **Submit URL**, **Headers**, and **After submission** - Add a **Form Reset Button** to clear the form - Test the form in Preview and Test modes --- # Building a Multi-View Application Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/tutorials/04-multi-view-app.md ## What are Views? An interface can contain multiple **views** (pages). Each view is a separate canvas with its own rows and blocks. One view is marked as the **default view** -- it carries a green **Start** badge in the views list and is the view displayed by default when the interface loads. Users navigate between views using: - **Action buttons** with the "go to view" action - **Navbar blocks** with interface-type links Views are managed from the **Interface Views** page, where every view in the current interface is shown as a card. ## Creating a Second View 1. Go back to the **Interface Views** page by clicking the back arrow in the top bar of the Builder. 2. Click **Create New** to open the **Create new view** dialog. 3. Give it a descriptive name (for example `Order summary`) and click **Create**. 4. Back on the Interface Views list, click the **Edit** button on the new view's card to open it in the Builder. Interface Views page with two view cards. The Create New button is in the top-right of the list, and each card shows the view name, description, row count, and Edit / Settings / Copy / Delete actions. ## Building the Second View 1. With the new view open in the Builder, add rows and blocks as needed. 2. For example, add a Title block bound to `{{deal.title}}` and a Paragraph block showing deal details. 3. This view will serve as a detail page that users navigate to from the first view. ## Adding Navigation with an Action Button On the first view, set up a button that navigates to the second view: 1. Go back to the Interface Views page and open your first view. 2. Add a **Button** block to the canvas. 3. In Button settings, set the **Button Type** to `Action Button`. 4. A new **Action Type** dropdown appears with two options: - **back** -- navigates to the previous view - **go to view** -- navigates to a specific view 5. Select **go to view**. 6. A **View Name** dropdown appears, listing all views in this interface. Select the second view you just created. 7. The button now navigates users to that view when clicked. Block Configuration sidebar for an Action Button. Button Type is 'Action Button', Action Type is 'go to view', and the View Name dropdown is open showing 'Customer details' and 'Detail View' as available targets. ## Adding a Back Button On the second view, add a way to return to the first view: 1. Open the second view in the Builder. 2. Add a **Button** block. 3. Set the **Button Type** to `Action Button`. 4. Set the **Action Type** to **back**. 5. This button returns users to whatever view they came from. The settings panel looks the same as for "go to view" — just without the **View Name** dropdown. ## Passing Parameters Between Views Action buttons can pass data from one view to another using parameters. The receiving view accesses these values via the **Search Params** tab in the Data Picker. 1. On the first view, select your "go to view" Action Button. 2. Below the View Name dropdown, you will see a **Parameters** section. 3. Click to open the parameters dialog. 4. Add key-value pairs. For example: - Key: `deal_id`, Value: a Data Picker tag pointing to the deal's **ID** field. - Key: `deal_title`, Value: a Data Picker tag pointing to the deal's **Title** field. 5. Values support Data Picker expressions, so you can pass dynamic data. On the receiving view: 1. Select a block (for example, a Title block). 2. Open the Data Picker and switch to the **Search Params** tab (the icon-only tab in the picker's top bar). 3. You will see the parameter keys you defined. Selecting one inserts a tag that compiles to `{{searchparams.deal_id}}`. Manage Parameters dialog with two rows: deal_id paired with a blue Data Picker tag for the deal's ID field, and deal_title paired with a Data Picker tag for the Title field. Add Parameter, Cancel, and Save Parameters buttons sit at the bottom. ## Using Navbar for Navigation For persistent navigation across your interface, use a **Navbar** block: 1. Add a **Navbar** block to a row on your view. It typically goes in a full-width row at the top. 2. Click the Navbar block to open its settings. The settings are divided into sections. ### Brand - Toggle **Show title** to display a text title in the navbar. Configure **Title Text**, **Font Size (px)** (12–48), **Font Weight** (Normal, Medium, Semibold, Bold), and **Title Color**. - Toggle **Show logo** to display a logo image. Provide the **Image URL**, **Alt Text**, and **Width / Height (px)**. ### Aria Label Below the Brand section, set the **Aria Label** for the navigation element (defaults to "Navigation menu"). This helps screen readers identify the navigation purpose. ### Layout - **Layout Direction** — Horizontal or Vertical - **Alignment** — Left, Center, Right, or Space Between - **Spacing (px)** — pixel spacing between nav items (0–50) ### Navigation Links 1. Click the **Manage Links** button to open the links dialog. 2. Click **Add** to create a new link. Each link has: - **Label** — the text displayed in the navbar - **Link Type** — choose between: - **Interface** — navigates to another view within this interface. Select the target view from the **Target Interface** dropdown. You can also add **Parameters** (key-value pairs) that are passed to the target view. - **External URL** — opens an external URL (supports Data Picker expressions) 3. Add links for each view you want in your navigation. 4. Reorder links by dragging the grip handle on each link card. 5. Delete links using the trash icon. Manage Links dialog with two Interface-type links. The first ('Customers') is expanded showing Label, Link Type set to Interface, and Target Interface set to 'Customer details'; the second ('Detail') is collapsed below. The Navbar's Brand, Aria Label, and Layout settings are visible in the sidebar behind the dialog. Preview of the view rendered with the Navbar in place: 'My App' brand title on the left and the 'Customers' and 'Detail' links on the right. The Action Button is visible above the navbar. ## Summary In this tutorial you learned to: - Create multiple views from the Interface Views page - Use Action Buttons with the "go to view" action to navigate between views - Add "back" buttons for return navigation - Pass parameters between views using key-value pairs and Data Picker expressions - Access passed parameters on the receiving view via the Search Params tab - Set up a Navbar block with interface-type links for persistent navigation - Configure navbar Brand, Aria Label, Layout, and link settings --- # Building a Table View Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/tutorials/05-table-view.md ## When to Use Tables The **Table** block displays array data in a structured grid with rows and columns. Common use cases include: - Displaying deal products or line items - Showing lists of related contacts or organizations - Rendering any array data from Pipedrive or custom sources Tables support configurable columns, per-row actions, sorting, conditional visibility, and custom styling. ## Adding a Table Block 1. Hover the canvas (or the gap between rows) to reveal the `+` button. Click it and pick **Full** in the **Add row** dialog — full-width works best for tables. 2. Click the empty column inside the new row to open **Add block**, then pick **Table**. 3. Click the Table block to open its settings in the sidebar. Add block dialog open over a full-width row on the empty canvas. The dialog grid lists Button, Title, Paragraph, Image, Divider, Table, HTML, Input (disabled outside forms), Navbar, Avatar, Hover Card, Chart, Alert, and Badge. The Table tile is highlighted with a hover state. ## Setting the Data Source The table needs an array data source to iterate over. 1. In Table settings, find the **Target Array** field. This is a Data Picker input that specifies which array to display. 2. Click the Target Array field to open the Data Picker. 3. Navigate to an array field. For example, under the **Deal** tab, find a field that contains array data (such as deal products or a custom field that returns a list). 4. You can also use the **Custom** tab if your data comes from a custom JSON source. 5. Select the array field. The placeholder is inserted into the Target Array field. The table renders one row per item in the array. Block Configuration sidebar on the right showing the Table block's settings: Name 'Table', Table Title (empty), Title Alignment 'Left', Default Cell Alignment 'Left', and a focused Target Array field. The Data Picker has opened next to the field with the Deal tab selected, listing fields like ID, Title, Creator, Value, Contact person, Organisation, Stage, Currency, Add time, Update time, Status, and Probability. ## Table Header (Optional) Above the data source, the sidebar exposes: - **Table Title** — optional text rendered above the table, for example `Deal Products`. It is plain text: the Data Picker is not available here. - **Title Alignment** — Left, Center, or Right alignment for the title text. - **Default Cell Alignment** — fallback alignment applied to every column that does not set its own alignment. Choose Left, Center, or Right. - **Empty table text** — text shown when the Target Array resolves to an empty list. This is a Data Picker input and supports dynamic values. ## Configuring Columns Columns define what data appears in each table column. Use the **Manage Columns** dialog to add and configure them. 1. Click the **Manage Columns** button in Table settings. 2. The dialog opens with a column list on the left and a settings panel on the right. 3. Click the **Add** dropdown to add a new column. You can choose between: - **Add value column** — displays data from each array item. - **Add action column** — displays clickable action icons. - **Add subrow** — displays an extra row of text rendered below each row (useful for descriptions or secondary info). 4. Select a column on the left to edit its settings on the right. Columns can be reordered by dragging the grip handle, duplicated with the copy icon, or deleted with the trash icon. Subrow columns cannot be reordered — they always render below the main row. Each column has its settings split across four tabs in the right panel: - **General** — the data fields that drive the column. - **Styling** — width, cell alignment, and cell padding. - **Sorting** — whether the column is sortable and how. - **Conditional** — when the column is visible. ### Value Columns: General Tab For each value column, fill in: - **Header** — the column header text. This is a Data Picker input, so you can use static text or dynamic values. - **Value(s)** — the data field to display for each row. This is a Data Picker input that resolves relative to each array item. For example, if your array contains objects with a `name` property, enter `name` or use the Data Picker to select the field. Manage Columns dialog. Left panel: a single column entry '(Value) Column 1' with row controls and an 'Add' button at the bottom. Right panel: tabs General (selected), Styling, Sorting, Conditional. The General tab shows Header set to 'Product' and Value(s) set to 'name', followed by the Column Overview cards summarizing Styling (Left, Auto, Padding off), Sorting (disabled), and Conditional (Always visible). ### Value Columns: Styling Tab - **Cell Alignment** — Left, Center, or Right for the cell content. - **Column Width** — pick **Auto**, or set a fixed width in `%` or `px`. - **Cell padding** — toggle to override the table default. When enabled, you can set Top, Right, Bottom, and Left padding individually. ### Value Columns: Sorting Tab - **Allow sorting** — toggle to let end-users click the column header to reorder rows. - **Sort by this column** — when enabled, this column is the table's default sort. Only one column can hold this flag. - **Sort direction** — **Ascending** or **Descending** for the default sort. - **Custom sort value** — when enabled, sort rows by a different value than the displayed one. Provide a Data Picker path for **Sort value**. Manage Columns dialog with the Sorting tab open for a value column. Allow sorting toggle is on (blue), Sort by this column checkbox is checked, Sort direction is set to Ascending. Below them, a Custom sort value toggle (off) and a disabled Sort value Data Picker input, with a helper note explaining that custom sort value is useful for sorting by a raw number while displaying a formatted value. ### Value Columns: Conditional Tab - **Enable conditional visibility** — toggle to hide the column based on a condition. - **Condition** — Data Picker expression. The column is hidden when the value resolves to empty or `"false"`. Any other value shows the column. ## Action Columns Action columns add clickable buttons to each row, allowing users to perform operations on individual items. A button can show an icon, a text label, or both. 1. In the Manage Columns dialog, click **Add** and select **Add action column**. 2. The General tab shows the column's **Header** plus an accordion of **actions**. Each action has: - **Icon** — choose from grouped **Actions**, **Communication**, **Files**, and **Status** icons. The set includes View, Edit, Delete, Add, Copy, Play, Refresh, External link, Mail, Send, Phone, Message, Bell, User, File, Folder, Download, Upload, Image, Attachment, Print, Archive, Check, Close, Warning, Info, Clock, Star, Heart, Lock, and Unlock. Select **Custom** to fill **Custom Icon** with an image URL through the Data Picker. - **Action Type** — pick **Go to view** to navigate within the interface, **Go to URL** to open a URL, or **Send request** to send a POST without leaving the table. - **Label** — optional button text, shown after you pick an Action Type. It supports the Data Picker and resolves per row. With a Label set, **Icon position** chooses which side the icon sits on, and the Icon picker offers **No icon** for a text-only button. - **View Name** — when Action Type is **Go to view**, pick the destination from the dropdown. Optionally configure **Parameters** (key-value pairs passed to the target view; values reference fields from the current row). - **URL** — when Action Type is **Go to URL**, fill the address. The URL field supports Data Picker expressions, so you can construct URLs with row data. - **Request URL** — when Action Type is **Send request**, enter an absolute HTTP or HTTPS endpoint. Use the Data Picker to include row values. - **Body Data** — optionally configure a JSON payload as JSON or key-value pairs. Include the row's identifier because OneClick metadata identifies the view resource, not the row. Leave it empty for no configured body. - **Omit OneClick metadata envelope** — leave off to send Body Data alongside OneClick metadata; turn on to send only Body Data. Test requests in the Test view; Preview shows them disabled. - **Require confirmation** — when Action Type is **Send request**, turn this on to ask before the request is sent. The **Title** and **Description** support the Data Picker, so the dialog can name the row it acts on. 3. Click **Add Action** to add more actions to the same column. 4. Each action can be duplicated or deleted from the action's accordion menu. The Styling, Sorting, and Conditional tabs apply to action columns in the same way as value columns. Manage Columns dialog with '(Action) Column 2' selected on the left. The General tab is open and shows the column's Header field, then an expanded 'Action 1 (View)' card with Icon set to 'View' (eye), Action Type 'Go to view', an empty View Name dropdown, and a Params section with an 'Add Param' button. An 'Add Action' button below allows additional actions on the same column. ### Passing Row Data to Another View When an action navigates to a view, you can pass data from the current table row: 1. Set the action's **Action Type** to **Go to view**. 2. Choose the target view from **View Name**. 3. Expand the **Parameters** section. 4. Add key-value pairs where the values reference fields from the current array item. The Data Picker context is scoped to the current row, so you can directly select fields from the row item. ## Subrow Columns A **subrow** column adds a second line of text below each main row — useful for descriptions, hints, or secondary details that do not need their own column. - **Path** — the data field rendered as the subrow's text (Data Picker). - The Styling tab supports **Cell Alignment** and **Cell padding** for the subrow text. Conditional visibility is not available for subrow columns. ## Customizing Appearance In addition to per-column styling, the Table block uses the standard block style settings: - **Background color** - **Font size and color** - **Borders** — top, right, bottom, and left borders with width, style, and color The table renders with structured headers and data rows. When the array is empty, the **Empty table text** (if configured) is shown. Preview mode header (back arrow, 'Preview' title, 'Deal #1995' context badge) above a rendered table. The table shows a single header row with a sort indicator in the first column and a centered 'No data' message in the body — the empty state shown when the configured Target Array resolves to an empty list. ## Summary In this tutorial you learned to: - Add a Table block and set its data source via the **Target Array** field - Configure the **Table Title**, **Title Alignment**, **Default Cell Alignment**, and **Empty table text** at the table level - Add **value**, **action**, and **subrow** columns from the **Manage Columns** dialog - Configure each column across the **General**, **Styling**, **Sorting**, and **Conditional** tabs - Add **Go to view**, **Go to URL**, and **Send request** actions with per-row data - Toggle **Allow sorting**, set a default sort column and direction, and use a custom sort value - Hide columns conditionally using the **Conditional** tab --- # Creating a New View Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/views/creating-a-view.md ## Interface Views Page Open the views list for an interface from the interface management page (the **Interface Domain > Interface Views** breadcrumb). The page shows every view in the interface as a card with its name, description, row count, and the **Start** badge on whichever card is the main view. The Interface Views list with two view cards: 'Customer details' (highlighted with a green border and a Start badge as the main view) and 'Order summary'. Each card shows the view name, description, '1 row' counter, an Interface type label, and Edit / Settings / Copy / Delete action buttons. A 'Create New' button sits at the top right of the Your Views (2) section, with a Beta Feature warning above the cards. ## Creating a New View 1. Click **Create New** in the top-right of the **Your Views** section. 2. The **Create new view** dialog opens. Fill in: - **Name** -- a unique, descriptive name. The name is used in navigation references (action buttons, navbar links, form-after-submit selectors) and in the view-selector dropdowns inside the builder. Choose clear names like `Customer details`, `Order summary`, or `Edit form`. - **Description** -- optional context shown on the view card. - **Default view** -- when on, this view becomes the interface's main view (see [Main View](#main-view) below). The first view of an interface is forced to be the default and the toggle is disabled. 3. Click **Create**. The view is created with an empty canvas and the builder opens automatically. ## Editing the View in the Builder Click **Edit** on a view card (or open a view from the breadcrumbs) to start working on it in the builder. From there you can: - Add rows and blocks. - Configure data bindings via the Data Picker. - Set Global Styles for view-wide font, colour, and gap defaults. - Configure Areas to group rows for shared visibility or looping. Each view has its own independent layout, rows, blocks, and settings. Edits auto-save -- there is no separate save or publish step. See [Saving](/docs/buttons/interface-button/interface-builder/how-to/views/publishing) for the auto-save and validation rules that apply. ## Card Actions Each view card has four action buttons: | Button | What it does | |---|---| | **Edit** | Opens the view in the builder. | | **Settings** | Opens the **Edit view** dialog. Same fields as **Create new view** plus a read-only **ID** -- use this dialog to rename, edit the description, or change which view is the main view. | | **Copy** (clipboard icon) | Duplicates the view inside the same interface. The copy is never the main view. | | **Delete** (trash icon) | Removes the view after a confirmation prompt. | ## Main View The main view is the one that opens when a user clicks the OneClick button in Pipedrive. In the views list it is highlighted with a green border and a **Start** badge (star icon) on the card preview. To change which view is the main view: 1. Click **Settings** on the view card you want to promote. 2. In the **Edit view** dialog, turn on the **Default view** switch. 3. Save. Only one view can be the main view at a time -- enabling **Default view** on a different card automatically clears it on the previous main view. Other views are reached through navigation actions: Action Buttons, Navbar links, Table action columns, and form submissions. See [Navigating Between Views](/docs/buttons/interface-button/interface-builder/how-to/views/navigation) for setup details. --- # Managing Interface Views Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/views/managing-interface-views.md Interface Views is the top-level list of all views under a single interface (for example, a deal-details panel, a product form, a summary page). This page covers the tools for managing that list from the home screen. ## The Interface Views list Open the Interface Views page from the home screen. The list shows one card per view. Each card contains: - A **preview area** with an abstract miniature of the view's layout. Hovering reveals an **Open Editor** overlay you can click to jump straight into the builder. - A **Start** badge in the top-left of the preview when the view is the interface's default view. - An **Error** badge instead, if the view's saved data fails to parse. - The view **name** and **description**. - Stats: the **row count** and an **Interface** label. - Action buttons: - **Edit** -- the primary call-to-action; opens the view in the builder. - **Settings** -- opens the view's settings dialog (rename, edit description, mark as default, etc.). - **Copy view** -- icon button with a tooltip; duplicates the view. - **Delete view** -- icon button with a tooltip; removes the view. Interface Views home screen with two view cards. The left card 'Customer details' shows a green Start badge in its preview, the row count '1 row', and the Edit, Settings, Copy, and Delete action buttons. The right card 'Order summary' has the same layout without a badge. ## Copying a view Click the **Copy view** icon on any card to duplicate it. The new view appears instantly as `" (Copy)"` and contains a full snapshot of every row, block, area, and data source. Use this when you want to iterate on a view without breaking the production version, or when you need several similar views that differ only slightly. ## Deleting a view 1. Click the **Delete view** icon on a card. 2. The card switches to an inline confirmation: **"Delete this view?"** with **Cancel** and **Delete** buttons. 3. Click **Delete** to remove the view, or **Cancel** to back out. This action cannot be undone from the views list. If you took a [snapshot](/docs/buttons/interface-button/interface-builder/how-to/views/snapshots) before the delete, restore that snapshot to get the view back with its original id. The restore returns all views and variables to the state of the snapshot, and you can undo it. Interface Views list with the right card 'Order summary' switched to its inline delete confirmation state. The action row reads 'Delete this view?' followed by Cancel and Delete buttons; the left card 'Customer details' is unchanged. --- # Navigating Between Views Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/views/navigation.md ## Action Button The Action Button is the primary way to navigate between views. 1. Add a **Button** block to your view. 2. Set **Button Type** to **Action Button**. 3. Choose an **Action Type**: - **go to view** -- navigates to a selected view. A **View Name** dropdown lists every view in the interface. - **back** -- returns to the previous view. 4. Optionally click **Handle params** under **Parameters** to add key/value pairs that get forwarded to the target view. Values support the Data Picker. Builder view 'Buttons demo' with an Action Button selected on the canvas. The Block Settings sidebar shows Name 'Button', Button Type 'Action Button', Action Type 'go to view', View Name 'Buttons demo', and a Parameters section with a 'Handle params' button. ## Navbar Links The **Navbar** block supports interface-type links for view navigation: 1. Add a **Navbar** block to your view. 2. Click **Manage Links** in Block Settings to open the link manager dialog. 3. Click **Add** and configure the new link: - **Label** -- the clickable text shown on the navbar. - **Link Type** -- pick **Interface** for in-interface navigation (or **External URL** for an outside link). - **Target Interface** -- the destination view dropdown. Shown when **Link Type** is **Interface**. - **Parameters** -- key/value pairs passed to the target view. Click **Add Parameter** to add rows. The Navbar block's Manage Links dialog open over the docs-navbar view. The first link 'Home' is expanded and shows Label 'Home', Link Type 'Interface', Target Interface 'Account Summary', and an empty Parameters section with an 'Add Parameter' button. A second link 'Documentation' is collapsed below it. ## Table Actions Table blocks can include row action columns that navigate to views. Configure a column as an action column, add an action with **Action Type = Go to view**, pick a **View Name**, and optionally add **Params** -- the action will navigate to the chosen view with those params, alongside the row's data, when a user clicks the icon. ## Form After Submit When a form is submitted, you can navigate to a different view: 1. Set the submit button's **After submission** to **Select view**. 2. Pick the target view from the **View ID** dropdown. 3. Optionally add **Parameters** -- key/value pairs passed alongside the navigation. 4. Turn on **Use input values as search params** to automatically forward every form field value as a URL search parameter on the navigation. Alternatively, set **Form Type** to **Open view with form data** to skip the HTTP submission entirely. The submit button hides its Submit URL and After submission settings, forwards every form input value as a search parameter to the chosen view, and navigates immediately when the user clicks submit. ## Passing Parameters All navigation methods support passing parameters: - **Action Button** -- click **Handle params** under **Parameters** and add key / value entries. - **Table action column** -- each action has its own **Params** key / value editor. - **Navbar links** -- each link has its own **Parameters** section inside the Manage Links dialog. - **Form Submit Button** (After submission = **Select view**) -- use **Parameters** for explicit pairs and / or **Use input values as search params** to forward every form field. The target view receives these as URL search parameters, accessible from the Data Picker's `searchparams` tab (icon-only) and compiled to `{{searchparams.key}}` placeholders at render time. --- # Saving Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/views/publishing.md ## Auto-Save Interface Builder saves automatically. After you stop editing for a brief moment, the change is written to the server -- there is no save button and no publish step. You do not push a view live; it **is** live. The moment a save completes, anyone opening the view in Pipedrive sees your latest edits. :::caution[Every save is immediately live] Preview and Test modes inside the builder render against the same saved data — they do **not** isolate changes from end users. Anyone opening the OneClick button while you're editing sees your in-progress edits. See [External Data Flow](/docs/buttons/interface-button/interface-builder/explanation/external-data-flow) for what each mode does and does not call. For risk-free experimentation, copy the OneClick button in Pipedrive and edit the copy's interface, then point users at the new button when the changes are ready. ::: ## Validation Before each save the builder runs a validation pass over the whole view -- rows, blocks, forms, and every setting. If something is wrong, an **Action required** card appears on the canvas with a quick-fix button, and the save is blocked until you resolve the issue. This means a broken view never reaches end users. An 'Action required' card on the canvas. The card has an amber file-input icon, the heading 'Missing input field', the body text 'Your form needs at least one input field for users to enter data.', and an 'Add input' quick-fix button at the bottom. The card icon, title, description, and quick-fix button vary by issue. For incomplete forms the card title is **Missing input field** (with an **Add input** button) or **Missing submit button** (with an **Add submit button** button); other issues surface as inline errors next to the affected field in Block Settings. ## Common Validation Errors These messages come straight from the validation layer. Each one blocks save until fixed. | Error | Cause | Fix | |---|---|---| | **Form requires at least one submit button** | A form has no submit button. | Add a Button block with **Button Type = Form Submit Button** and pick this form in the **Form** dropdown. | | **Form requires at least one input field** | A form has no Input blocks. | Add at least one Input block between Form Start and Form End. | | **Form start requires a corresponding form end** | A `Form Start` row exists without a matching `Form End`. | Add the `Form End` row, or delete the orphan `Form Start`. | | **Input field must be inside a form** | An Input block sits outside any form. | Move it between a `Form Start` and `Form End` row. | | **Input name must be unique** | Two Input blocks share the same internal name (usually from copy-paste). | Delete one and re-add it so the builder generates a unique name. | | **Submit button requires a form to exist** / **Reset button requires a form to exist** | A Form Submit or Form Reset Button points at a Form Identifier that does not exist. | Create a form with that identifier or pick an existing form. | | **URL is required** | A URL Button or external Navbar link, or a Submit URL on a JSON / Multipart form, has no URL set. | Fill the missing URL field. | | **You can't use the file input type because the form doesn't submit anything -- it opens a new view with the input values as search parameters.** | A form with file inputs uses **Open view with form data** as its Form Type. | Remove the file input or change **Form Type** to **JSON** or **Multipart/Form-Data**. | ## Testing a Live View Once a save completes, the view is live. To test it the way users see it: - Use **Test mode** inside the builder (the **Test** button in the top bar) to run the view with real records. - Or open the OneClick button in Pipedrive to see exactly what users see. Either way verifies: - Layout and styling. - Data Picker placeholders resolve correctly. - Form submissions work. - View navigation behaves as expected. - Conditional visibility rules behave as expected. ## Main View An interface can contain more than one view. The **main view** is the one that opens when a user clicks the OneClick button in Pipedrive. It is highlighted in the views list with a green border and a **Start** badge (star icon) on the card preview. To change which view is the main view, click the **Settings** button on a view card to open the **Interface Settings** dialog, then turn on the **Default view** switch. Only one view can be the main view at a time -- enabling **Default view** on a different card automatically clears it on the previous main view. Users reach the other views through navigation (Action Buttons, Navbar links, or form submissions). --- # Snapshots Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/views/snapshots.md A snapshot is a copy of all the views and all the variables of one interface. Take a snapshot before a big change. If the change breaks something, restore the snapshot and the interface is back in the state of the snapshot. A snapshot does not hold the OneClick settings of the interface (URL, token, headers, fields, visibility). Open the **Snapshots** tab on the home screen, next to **Views** and **Variables**. Snapshots tab with the Take snapshot button in the top-right and a list of four snapshots, newest first. Two rows named 'Before restore: …' have an Auto badge, 'E2E state A' and 'E2E baseline' have a Manual badge. The 'E2E state A' row shows a truncated description ending in '…'. Each row shows the time and the creator 'Test Zimple', a size such as '4 views · 5 variables', a Restore button, and pencil and trash icons. ## Taking a snapshot 1. Click **Take snapshot**. 2. Optionally type a **Name** and a **Description**. An empty name saves the snapshot as `Snapshot `. 3. Click **Take snapshot** in the dialog. The snapshot holds each view and each variable as a whole: for a view, for example its layout, sample data, data source URL and method, additional data, active flag, default view flag, name and description; for a variable, its key, value, type, resource, confidential flag and creator. Confidential values stay encrypted in the snapshot. The content of a snapshot never changes after you take it. ## The snapshot list The list shows the snapshots of the current interface, newest first. Each row shows: - The **name** and a **Manual** or **Auto** badge. An Auto snapshot is the one a restore takes automatically (see [Undoing a restore](#undoing-a-restore)). - The **description**, truncated to one line. Hover it to see the full text. - The creation time and the user who took the snapshot. - The size, for example `4 views · 5 variables`. - **Restore**, **Edit snapshot** (pencil) and **Delete snapshot** (trash). ## Restoring a snapshot A restore returns all the views and variables of the interface to the state of the snapshot: - Views and variables made after the snapshot are removed. - Views and variables deleted after the snapshot come back, with their original ids. References to a restored view from other views keep working. - Views and variables changed after the snapshot change back. - Confidential variables of other admins stay as they are. See [Variables and snapshot restore](/docs/buttons/interface-button/interface-builder/how-to/data/variables#variables-and-snapshot-restore). 1. Click **Restore** on the snapshot row. A summary card opens above the list, titled **Restoring to <snapshot time>**. 2. Check the counts. For views and for variables, the card shows how many **Will be removed**, **Will be restored** and **Will change back**. A red line lists the views that the restore deletes. If confidential variables of other admins stay as they are, a separate line lists their keys. 3. Click **Continue**, or **Cancel** to close the card without changes. Snapshots tab with the summary card 'Restoring to 2026-09-18 13:04' above the list. The Views column shows Will be removed 1, Will be restored 1, Will change back 3. The Variables column shows Will be removed 2, Will be restored 3, Will change back 1. A red line reads 'Views created after the snapshot are deleted: E2E Delta.' Below are the Continue and Cancel buttons. 4. The dialog **This replaces the current state** opens. Type the name of the interface exactly as shown, with the same upper and lower case letters. 5. Click **Restore now**. **Restore now** stays disabled until the name matches. Click **Back** to return to the summary card. Dialog 'This replaces the current state' over the summary card. The text reads 'Everything in Interface Domain made after 2026-09-18 13:04 is lost. A snapshot "Before restore: E2E state A" is created first, so you can undo this restore.' The field under 'Type Interface Domain to confirm' contains 'Interface Domain', and the Back and Restore now buttons are below it. After the restore, a toast confirms it and the **Views** and **Variables** tabs show the restored data. A restore is all or nothing. If it fails, nothing changes and one of these toasts appears: | Toast | Cause | |---|---| | **Restore failed. No changes were made.** | The restore failed. The summary card stays open, so you can try again. | | **Snapshot no longer exists. No changes were made.** | Somebody deleted the snapshot in another session. The list refreshes. | | **Button no longer exists.** | The interface was deleted. The app returns to the OneClick settings. | ## Undoing a restore Before every restore, a snapshot named `Before restore: ` is taken automatically. It has the **Auto** badge and holds the state that the restore replaced. To undo a restore, restore that Auto snapshot. ## Editing and deleting a snapshot - **Edit snapshot** (pencil) changes the name and the description. The copied views and variables do not change. The name cannot be empty. - **Delete snapshot** (trash) asks for confirmation and then deletes the snapshot permanently. This cannot be undone. Any admin can edit, delete and restore any snapshot of the interface, also Auto snapshots and snapshots taken by other admins. When the interface is deleted, its snapshots are deleted too. --- # Testing a View with Real Data Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/views/testing-a-view.md The builder's **Test** mode renders your view with real data while you are editing it. Use it to verify that placeholders resolve, forms submit correctly, and conditional visibility behaves as expected -- before anyone else opens the view. Interface Builder has no separate publish step. Every edit you make is auto-saved and goes live immediately for anyone who opens the view in Pipedrive, so Test mode is the safest place to experiment. ## Opening Test Mode 1. Open the view in the builder. 2. Click the **Test** button in the top bar (next to **Preview** / **Sample data**). The builder switches to Test mode: a single toolbar runs along the top of the canvas, with the rendered view below it. Test mode for a view containing a Chart block. The toolbar from left to right: a back arrow, the heading Test, a 'Deal #1995' resource button, a '/api/r/antti-fortnox' URL button, a green 'Review received data' button, the Test action button, an 'Automatically update on change' toggle (on), and a green 'Done' status. Below the toolbar a bar chart titled 'test' shows four customers (Acme Corporation Ltd, Nordic Solutions AB, TechVenture GmbH, Greenfield Industries) with their amount values. The back arrow on the left returns to the builder. ## Picking a Pipedrive Record The toolbar shows the active resource as a button labelled ` #` (for example, `Deal #1995`). Click it to open the **Pipedrive resource** dialog and pick a different record. 1. Pick a resource type -- **deal**, **person**, or **organization**. 2. Pick a specific record from the list. 3. Close the dialog. The preview reloads with that record's data. Every Data Picker placeholder bound to a Pipedrive field (for example `{{deal.title}}`) resolves to the real value. A [floating window button](/docs/buttons/interface-button/interface-builder/explanation/floating-window-buttons) has no record to pick, so its Test and Preview toolbars do not show the resource button at all. ## Tweaking the External Data Source If your view has a Data Source URL configured, click the URL button on the toolbar (Link icon, label is the path of the configured URL). The **View parameter** dialog opens and lets you tweak the request without editing the saved view configuration: - **URL path** -- override the path the test calls. - **Query parameters** -- add, edit, or remove key/value pairs. Duplicate keys collapse into a single row whose value reads `(multiple)`. Closing the dialog re-runs the request and re-renders the view. ## Reviewing the Backend Response Click **Review received data** (eye icon, green button) to see the JSON your data source actually returned, along with the HTTP status. Use this when placeholders look empty or wrong -- it tells you whether the backend sent what you expected. The dialog is empty until a backend response arrives -- it never falls back to your saved Sample data. If your view has no data source configured, switch to **Preview** to see how Sample data renders. ## Manual vs Automatic Reload The **Automatically update on change** switch on the right of the toolbar controls when reloads happen. - **On** (default) -- the preview reloads automatically whenever you change the resource, the URL path, or any query parameter. - **Off** -- changes are buffered. Click the **Test** action button to fetch the data and re-render manually. Useful when you are making many small edits. Your preference is stored in browser localStorage (`autoloadEnabled`), so it persists across sessions. ## What Test Mode Is Not - It does **not** gate your edits. There is no publish step -- whatever you have saved in the builder is already what users see. Test mode is just a convenient way to render the same view with real records while you keep editing. - It does **not** replace real end-user validation -- the preview runs in the builder, not in the Pipedrive panel where your users actually see the view. ## Troubleshooting - **Toast `Request timed out. No custom data received.`** -- your Data Source URL backend did not respond within ~20 seconds. Check your backend logs. - **Toast `Data loading failed (status 500)`** -- your Data Source URL returned a non-2xx status. The status code is shown in the toast. - **Placeholders show literal text** -- the data needed to resolve them is missing. Check that you selected a Pipedrive record, or that your Data Source URL returned the fields you expect. Use **Review received data** to confirm what arrived. See [External Data Source](/docs/buttons/interface-button/interface-builder/how-to/data/external-data-source) for configuring the URL that Test mode calls. --- # How to Create a Form Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/forms/creating-a-form.md ## Add the Form 1. Hover the gap between two rows on the canvas (or above the first row). A small `+` button appears. 2. Click `+` to open the **Add row** dialog. 3. Pick **Form** from the layout list. Add row dialog open on top of the empty canvas. The dialog lists six layout options stacked vertically: Full width, Two columns, Three columns, Sidebar left, Sidebar right, and Form. The Form option is at the bottom of the list and is highlighted with a hover state, showing its label and the description 'Form container for input fields'. The dialog closes and two new marker rows appear on the canvas: - **Form Start** — marks the beginning of the form (shown with a left-edge accent and a row label). - **Form End** — marks the end of the form (shown with a left-edge accent and a row label). Builder canvas after adding a form. A blue 'Form Start · Row 1' marker sits at the top with a left-edge accent and a default identifier badge ('Form e592'). A matching 'Form End · Row 2' marker sits below. Between the two markers the empty form area shows the 'Action required: Missing input field' warning card. The Form Settings tab is open in the right sidebar. The **Form** option is hidden in the **Add row** dialog when you are already inside a form — forms cannot be nested. ## Set the Form Identifier 1. Click either the **Form Start** or **Form End** row to open the **Form Settings** tab in the sidebar. 2. Enter a unique name in the **Form Identifier** field — for example, `contact-form`. 3. The identifier appears as a badge next to **Form Start** on the canvas and is used by Submit and Reset buttons to target this form. Form Settings tab open in the right sidebar with the Form Identifier field set to 'contact-form'. Below it are Padding Top, Padding Bottom, Padding Left, and Padding Right inputs (all 0 px). On the canvas, the Form Start row now shows the 'contact-form' identifier as a badge next to the row label. ## Adjust Form Padding (Optional) In the **Form Settings** tab you can set inner padding for the rendered form: - **Padding Top** (px) - **Padding Bottom** (px) - **Padding Left** (px) - **Padding Right** (px) ## Add Rows Inside the Form Hover the area between the Form Start and Form End markers, then click the `+` button that appears to open **Add row**. Pick any layout (Full, Two Column, etc.) — note that the **Form** option is hidden inside an existing form. Rows added in this area become part of the form. ## Place Input Fields Click an empty column inside the form to open **Add block**, then pick **Input**. The dialog only allows the **Input** block when the surrounding row is inside a form. For details on input types and settings, see [Input Field Types](/docs/buttons/interface-button/interface-builder/how-to/forms/input-field-types). ## Validation Warnings While you build, the canvas highlights warnings when the form is incomplete. Each warning includes a quick action button to fix the problem: - **Missing input field** — the form has no input blocks between Form Start and Form End. Add at least one Input block. - **Missing submit button** — no button anywhere in the view targets this form's Form Identifier. Add a Button block, set its **Button Type** to **Form Submit Button**, and pick this form from the **Form** dropdown. Close-up of the 'Missing input field' warning card displayed inside an empty form on the canvas. The card has a yellow dashed border, a document-with-arrow icon at the top, an 'ACTION REQUIRED' label, the heading 'Missing input field', the description 'Your form needs at least one input field for users to enter data.', and an 'Add input' quick-action button. --- # Configuring Form Submission Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/forms/form-submission.md A submit button's settings live in the **Configuration** sub-tab of the Block Settings sidebar. Open them by selecting a **Form Submit Button** on the canvas. Builder view 'Buttons demo' with a Form (Form ktyy) containing an Input and a selected submit Button. The Block Settings sidebar shows the Configuration sub-tab with Name 'Button', Button Type 'Form Submit Button', Form 'Form ktyy', Form Type 'JSON', a Submit URL button with a green check badge, After submission 'Wait for response', Timeout 10, Form State (Disable form after submission off), User Feedback (Show message after submission off), and the Validation Behavior toggles (Show error indicator on submit button and Scroll to first error field) all off. ## Pointing the Button at a Form The **Form** dropdown lists every form on the view (each `Form Start` row). Pick the one this submit button should send. ## Form Type Set **Form Type** to control how data is sent: - **JSON** (default) -- sends form data as a JSON payload. Requires a Submit URL. - **Multipart/Form-Data** -- sends as multipart form data. Use this when the form includes file uploads. Requires a Submit URL. - **Open view with form data** -- passes form data to another view as URL search parameters without making any HTTP request. The Submit URL and After submission settings are hidden in this mode; submission always opens a target view. Full request shapes for each type: [Form Submission Types reference](/docs/buttons/interface-button/interface-builder/reference/data-binding/form-submission-types). ## Submit URL For **JSON** and **Multipart/Form-Data**, click the **Submit URL** button to open the **URL Configuration** dialog. The dialog has three cards: - **Button end-point configuration** -- the End-point URL the form posts to (supports the Data Picker), a **URL Active** toggle, and an **Omit oneclick metadata** switch (turn this on for APIs that reject extra fields like `event_id` or `resource_id`, e.g. Pipedrive API v2). - **Query Parameters** -- key/value pairs appended to the Submit URL. Click **Add Parameter** to add a row; values support the Data Picker. - **Manage Headers** -- custom HTTP headers sent with the request. Click **Add Header** to add a row. Header keys must contain only letters, numbers, and hyphens, cannot start or end with a hyphen, and cannot start with `x-oc-` (reserved for system headers). Header values support the Data Picker, so you can use dynamic values like `{{variable.api_key}}`. :::note[OneClick-level headers are merged in automatically] If the OneClick button this interface is attached to has its **Headers** toggle enabled (configured outside the builder, on Pipedrive's **Edit a Button** page), every header listed there is sent with the form submit request. Use the per-call headers here only for values that differ between forms. See [OneClick-Level Headers](/docs/buttons/interface-button/interface-builder/explanation/architecture#oneclick-level-headers) for the merge order and the reserved `x-oc-*` keys. ::: The Submit URL button shows a method badge (always `POST` for submit buttons) and a green ✓ when a URL is set; it turns red if the Submit URL is missing. ## After Submission For **JSON** and **Multipart/Form-Data**, the **After submission** dropdown picks what happens once the request is sent: ### Select view Navigates the user to another view as soon as the request finishes. - **View ID** -- the target view dropdown. - **Parameters** -- key/value pairs passed to the target view. - **Use input values as search params** -- a design-time hint. When on, the form's inputs are listed under **Expected Parameters from Views** in the target view's URL Configuration dialog. Form input values are forwarded on the navigation regardless of this switch — toggling it off does not remove them from the URL. ### Wait for response Waits for the server to respond, then reacts to what came back. - **Timeout (s)** -- how long to wait, between **10** and **60** seconds (default 10). The fetch is aborted if the response does not arrive in time. - **Form State** > **Disable form after submission** -- when on, the submit button stays disabled after the response returns. Useful when the submit is final and you do not want the user to try again. - **User Feedback** > **Show message after submission** -- when on and the response contains a message, replaces the whole form with an inline alert instead of showing a toast. See the [Post-submit message](#post-submit-message) section below. What you return from the server decides what the user sees next. See [HTTP Response Format](/docs/buttons/interface-button/interface-builder/reference/data-binding/http-response-format) for the response shapes. ## Validation Behavior The **Validation Behavior** group controls how validation errors and submission errors are surfaced before the request is even attempted. Each toggle has a tooltip explaining what it does. | Switch | Effect | |---|---| | **Show error indicator on submit button** | Adds a red border and a tooltip with the error count to the submit button while there are validation errors on the form. A passive hint before the user clicks. | | **Scroll to first error field** | When the user clicks submit on an invalid form, smoothly scrolls and focuses the first invalid field. The strongest way to draw attention to a long form's validation issue. | | **Show error toast on submit** | Pops a toast with the number of invalid fields (for example `3 fields have errors`). The toast does not say *which* fields -- combine it with **Scroll to first error field** to make that obvious. | Combine **Scroll to first error field** with **Show error toast on submit** for the strongest feedback: the toast tells the user there *are* errors, the scroll-plus-focus shows *which* one to fix first. ## Submission Feedback ### While the submit is in flight Once the user clicks submit on a **Wait for response** form, the submit button shows a spinner in place of its label (the label's width is preserved so the layout does not jump) and the whole form switches to a `progress` cursor so the user cannot mistake the state for idle. The submit button and every descendant input stay in that state until the response returns -- on success or error -- or the submission throws. A thrown network or JSON-parse error resets the state so the button never gets stuck. **Select view** forms behave the same way up to the point of navigation; the spinner is visible until the browser leaves the page. ### Backend error response feedback When the backend returns `oneclick_data.error_message` or `oneclick_data.message_view` (see [HTTP Response Format](/docs/buttons/interface-button/interface-builder/reference/data-binding/http-response-format#error-responses)), two things happen: 1. A full-page message view replaces the rendered content with the message's `title` and `message`, plus **Go Back** and **Retry** buttons. `message` can be an array, shown as a bullet list, and `variant` sets the colours and the icon. You can suppress either button by returning `hideRetry: true` or `hideBack: true` on the object. 2. On error responses, an additional toast also appears with the response's top-level `message` (or `Something went wrong` when none was supplied). ### Post-submit message When **After submission** is set to **Wait for response** and the backend returns a message, how it is shown depends on **Show message after submission**: | Show message after submission | Response has `title`? | User sees | |--|--|--| | Off | No | Toast with `message` | | Off | Yes | Toast with `title` as primary text, `message` as description | | On | No | Inline alert replacing the form, `message` only | | On | Yes | Inline alert replacing the form, `title` + `message` | When the inline alert appears, the view smoothly scrolls to it so the user does not miss the new content even if they were at the bottom of a long form. The message and title can include a small amount of inline HTML -- bold, italic, line breaks, links, and inline code. See [Messages & Toasts](/docs/buttons/interface-button/interface-builder/how-to/data/messages-and-toasts) for how to format messages your backend returns. --- # Form Validation Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/forms/form-validation.md ## Required Fields 1. Select an input field inside your form. 2. Toggle **Required** on in the input settings. 3. When enabled, the form cannot be submitted until the user fills in this field. :::caution[Hidden inputs ignore Required] The Required toggle is forced off when the input type is Hidden — there is no way to require a hidden field. ::: ### Required from data Use data when some records need the field and others do not. 1. Click the ⇄ button beside the **Required** label. A Data Picker field replaces the switch. 2. Bind the field to a value, for example {{deal.must_fill}}. 3. The field is required when the value is `true`, `yes` or `1`. Case and surrounding spaces do not matter. Any other value leaves the field optional. This includes an empty value, `no`, `0`, `false` and a value that does not resolve, so an empty Data Picker field shows no warning. The value comes from the view data (Sample data, Received data, variables, System context). It does not read other inputs in the same form. Click ⇄ again to go back to the switch. The switch keeps its earlier position, and the Data Picker value is kept too. **Disabled** has the same choice and follows the same rule. A disabled field sends its **Default Value** when the form is submitted, and its validation (Required, Pattern, bounds) does not run. ## Pattern Validation Use regex patterns to enforce custom input formats: 1. Select a text-based input field (**Text**, **Textarea**, **Email**, **Number**, **URL**, or **Date** type). 2. Enter a regex expression in the **Pattern** field (e.g., `^\d{3}-\d{4}$` for a phone format like `123-4567`). The field accepts a literal regex, or a Data Picker placeholder (e.g. `{{validation_rules.email_pattern}}`) that resolves to one at submit time. 3. Once Pattern has a value, a **Pattern Error** field appears underneath. Set it to override the default error message shown when the input does not match. Pattern Error also supports the Data Picker, so the message can be localised or context-dependent. If no custom error message is set, a default validation error is shown. When the **value** a user submits is itself a Data Picker placeholder (e.g. a prefilled field bound to a template variable), the regex check is skipped -- the resolved value is trusted to be validated by the backend. Builder view 'Pattern Demo' with a Form Start row, a selected Email Input (Text type), a Submit Button row, and a Form End row. The Block Settings sidebar shows the Configuration sub-tab with Pattern set to '^\\d{3}-\\d{4}$' (with a regex101.com helper link beneath it) and the Pattern Error field that appeared in response set to 'Use format 123-4567'. Placeholder, Help text, and Default Value are empty; Required is off. ## Number Min/Max Validation For **Number** type inputs, bound the accepted range: 1. Select a **Number** input field. 2. Set **Min** and/or **Max** to the desired bounds. Both accept either a literal number or a Data Picker placeholder that resolves to one (e.g. `{{user.min_age}}`). 3. Once Min has a value, a **Min Error** field appears; once Max has a value, a **Max Error** field appears. Use these to customise the messages shown when the submitted value falls outside the bounds. Bounds are enforced at submit. If the value is below **Min** or above **Max**, the form does not submit and the error message appears next to the field. Changing the input **Type** away from **Number** clears all four fields (Min, Max, Min Error, Max Error) automatically. ## Built-in Type Validation Certain input types have automatic validation: - **Email** -- validates email address format. - **URL** -- validates URL format. - **Number** -- only accepts numeric input. No extra configuration is needed -- these validate automatically on form submission. ## File Type Limits Set **Accepted file types** on a File input to take only some kinds of file. Write one comma-separated list of extensions and MIME types: ``` .pdf, .docx, image/* ``` - A bare word such as `pdf` reads as `.pdf`. Case does not matter, and extra commas are ignored. - An entry that is neither an extension nor a MIME type, such as `*.pdf` or `image/`, shows an error under the field. - An empty list accepts every file. The file dialog offers only the listed types. The drop zone hint starts with the list, such as `.pdf, .png, image/* · One file · max 10 MB`; after three types it shows `+N more`. While a user drags a file of another type over the drop zone, the zone turns red and reads `File type not accepted (.pdf, .png)`. During a drag the browser shows only the file's MIME type, so the warning needs a MIME type for every entry: it never comes while the list holds an extension whose MIME type the field does not know. A file of another type can still arrive, for example by a drop. It joins the selection, its row turns red, and the form does not submit until the user removes it. The message names the file and the list: ``` File "setup.exe" is not an accepted type (.pdf, .png) ``` This is a check in the browser only. The server does not read the list, so do not rely on it to keep a file type out of your endpoint. ## File Size Limits A file input is guarded in two places -- your own limits in the browser, and the server's budget -- and they fail with different messages. ### 1. Your own limits, in the browser You set up to three limits on the field. Each one has its own message, so the user is told which limit they passed and by how much. The form does not submit until the selection clears all three. **Max File Size (MB)** applies to **each file on its own**, never to the selection added up -- three 5 MB files pass a 10 MB limit. An oversized file also turns its own row in the field red as soon as it is picked, and the message names the file: ``` File "contract.pdf" is 12.4 MB, which exceeds the 10 MB limit ``` **Max Total Size (MB)** applies to the selection added up. Only a field with **Allow multiple files** on has it: ``` The selected files total 12.4 MB, which exceeds the 10 MB limit ``` **Max Number of Files** caps how many files the field takes. It too belongs to a multi-file field alone, and it is the only limit that stops a user attaching hundreds of tiny files: ``` 14 files selected, which exceeds the limit of 10 files ``` The range you may set for the two size limits depends on the surrounding form's **Form Type**: **JSON** forms allow up to **10 MB**, **Multipart/Form-Data** forms allow up to **100 MB**. The count may go up to **25** on JSON forms and **50** on Multipart/Form-Data, and arrives pre-filled with **10**. The label inside Block Settings shows the active ceiling for each, and the size fields arrive pre-filled with it -- lower a number yourself if you want a tighter check. When a selection breaks more than one limit at once, the user reads the file type message first, then the per-file size message, then the count, then the total size. A file of the wrong type must go whatever its size, and the two per-file messages are the ones that name a file, so they say what to drop. ### 2. The submission budget, on the server Setting your own limits low enough does *not* guarantee the submission goes through. The server never sees them; it weighs every file field of the submission together against one budget of its own, so files that each passed check 1 can still be refused as a group. The user gets an error toast naming both numbers, and the form is never sent: ``` The submission carries 12.6 MB of files, more than the 10 MB this form accepts. Send fewer or smaller files. ``` To stay clear of it, keep the whole form's uploads under the budget for its **Form Type**, and move a form that needs more than 10 MB onto **Multipart/Form-Data**. The numbers, the reason they differ, and the one case that fails without this message are in [File Size Limits](/docs/buttons/interface-button/interface-builder/reference/data-binding/form-submission-types#file-size-limits). :::caution[No file inputs in "Open view with form data"] A form whose **Form Type** is **Open view with form data** *cannot* contain a file input -- the builder shows a clear validation error if you try. ::: ## Builder Validation Warnings The builder itself validates form structure and shows **Action required** cards directly on the canvas inside an empty form: - **Missing input field** -- with an **Add input** quick-fix button. Add an input block between the `Form Start` and `Form End` rows. - **Missing submit button** -- with an **Add submit button** quick-fix button. Add a button anywhere in the view, set **Button Type** to **Form Submit Button**, and select this form in the **Form** dropdown. Each card includes a one-click action button that drops the missing block in the right place. An 'Action required' card on the canvas. The card has an amber file-input icon, the heading 'Missing input field', the body text 'Your form needs at least one input field for users to enter data.', and an 'Add input' quick-fix button at the bottom. Other validation rules block save until they are resolved -- see [Saving](/docs/buttons/interface-button/interface-builder/how-to/views/publishing) for the full list (duplicate input names, submit/reset buttons that point at a non-existent form, file inputs in `Open view with form data` forms, missing URLs). ## Unique Input Names Each input has a **Name** field (the first row in Block Settings) that becomes the field key when the form is submitted. The builder generates an initial name like `Input` and appends a numeric suffix on duplicates -- a second input becomes `Input_2`, a third becomes `Input_3`, and so on. You can rename inputs from the **Name** field whenever you want to make the submitted JSON more readable. :::caution[Input names must be unique] If two inputs end up sharing a name (typically by manual editing), the builder flags an `Input name must be unique` validation error and blocks save until you change one. ::: --- # Input Field Types and Configuration Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/forms/input-field-types.md ## Adding an Input Field 1. Make sure you have a row inside a form. If you do not, see [Creating a Form](/docs/buttons/interface-button/interface-builder/how-to/forms/creating-a-form) first. 2. Click an empty column inside that row to open the **Add block** dialog. 3. Pick **Input** from the list. (The **Input** entry is only enabled when the row sits between a `Form Start` and a `Form End`.) 4. Click the new block to open its settings in the sidebar. 5. Choose the input **Type** from the dropdown. Builder view 'Input Block Demo' with a Form Start row, an Email Input block (Text type) selected on the canvas, a Submit Button row, and a Form End row. The Block Settings sidebar shows the Configuration sub-tab populated: Name 'Input', Label 'Email', Type 'Text', empty Placeholder / Help text / Pattern / Default Value fields, Required toggled on, and Disabled off. --- ## Basic Types - **Text** -- standard single-line text input. - **Textarea** -- multi-line text input. - **Email** -- text input with email format validation. - **Number** -- numeric-only input. - **URL** -- text input with URL format validation. - **Date** -- date picker. - **Hidden** -- invisible field, useful for passing data without user interaction. Hidden inputs can never be **Required** or **Disabled**: a change to Hidden turns both switches off and sets both settings back to a switch. - **File** -- file upload field. See [File Input](#file-input) below for the form-type rules. ### Textarea Input For **Textarea** type inputs, configure: - **Rows** -- the number of visible text rows (1--20, default 3). - **Max Length** -- the maximum number of characters the user can enter. Leave blank for no limit. ### File Input The rendered field is a row that reads **Drop a file here** (or **Drop files here**), with a **Browse** button on the right. The user either drops files onto the row or clicks anywhere on it to open the file dialog. Under the title, a hint lists the limits you set, such as `One file · max 10 MB` -- a limit you leave empty is left out of the hint. A dropped file goes through the same checks as a picked one. A rendered form field labelled 'Attachment' with no file selected. Under the label sits a bordered row: on the left a grey tile with an upload icon, in the middle the title 'Drop a file here' and under it the grey hint 'One file · max 10 MB', and on the right an outline 'Browse' button. No validation message is shown. A single-file input refuses a drop of several files at once: the row turns red and reads **Only one file allowed. Drop a single file.** as soon as the files are dragged over it, and a drop selects nothing. Once a file is selected, the row is hidden; the user removes the file with **X** to choose another. For **File** type inputs: - The maximum upload size is **Max File Size (MB)**. It applies to **one file at a time**, not to the selection as a whole. The allowed range depends on the surrounding form's **Form Type**: **JSON** forms allow up to **10 MB**, **Multipart/Form-Data** forms allow up to **100 MB**. The label inside Block Settings shows the active limit, and the field arrives pre-filled with it -- lower the number yourself if you want a tighter check. Switching the form type lowers a value that is too high for the new type, but never raises one you set yourself. - **Accepted file types** limits the field to the kinds of file you list, such as `.pdf, .png, image/*`. Leave it empty to accept every file. The file dialog offers only the listed types. A file of another type still joins the selection, but its row turns red and the form does not submit until the user removes it. See [File Type Limits](/docs/buttons/interface-button/interface-builder/how-to/forms/form-validation#file-type-limits). - A form whose **Form Type** is **Open view with form data** *cannot* contain a file input -- that mode forwards values as URL search parameters and cannot carry files. The builder shows a clear error if you try. #### Accepting several files Turn **Allow multiple files** on to let one field carry more than one file. The setting appears on the **File** type only and is off by default. The field then behaves like this: 1. The row reads **Drop files here**, its hint shows the limits (`Up to 10 files · 100 MB total · 10 MB each`), and the file dialog lets the user select several at once. 2. Each selected file gets a row showing its name and size. When **Max File Size (MB)** is set, the row shows `size / limit`, and a file over the limit turns red. A file that is not one of the **Accepted file types** turns red too. 3. Under the rows, a running summary reads `3 files · 12.4 MB / 100 MB` -- the count, the size of the selection so far, and the total-size limit when one is set. It turns red as soon as the selection breaks **Max Number of Files** or **Max Total Size (MB)**; a file that is too large or of another type turns its own row red instead. 4. The **X** on a row removes that one file; the rest stay selected. 5. Under the summary, a slimmer row reads **Add files** -- dropping or picking again *adds* to the selection instead of replacing it. A file that is already in the list is skipped. A rendered form field labelled 'Attachments' with three files selected. Each file sits on its own bordered row with a document icon, the file name (quarterly-report.pdf, signed-contract.pdf, site-photo.jpg) and, underneath, its size against the limit (208.98 KB / 10 MB, 86.91 KB / 10 MB, 402.34 KB / 10 MB). Every row has an X button on the right. Below the three rows, small grey text reads '3 files · 698.23 KB / 10 MB', and under that a slim bordered row with a plus icon tile, the title 'Add files' and an outline 'Browse' button on the right. No row is red, the summary is grey rather than red, and no validation message is shown. **Which limits to set.** A multi-file field has three: | Setting | Set it to | |---|---| | **Max File Size (MB)** | The largest single file the endpoint can handle. | | **Max Total Size (MB)** | What the endpoint can take in one request. Keep it at or under the budget for the form type, or the server refuses the submission even though the field accepted it. | | **Max Number of Files** | How many attachments the field is for. Pre-filled with 10; the highest you may set is 25 on JSON forms and 50 on Multipart/Form-Data. | Each limit has its own message, so the user is told which one they passed rather than being left to guess. Put a form meant for several sizeable files on **Multipart/Form-Data**. See [File Size Limits](/docs/buttons/interface-button/interface-builder/reference/data-binding/form-submission-types#file-size-limits). **Before you turn it on for a live field:** the setting changes what the endpoint receives, so update the integration first. See [File Fields](/docs/buttons/interface-button/interface-builder/reference/data-binding/form-submission-types#file-fields). --- ## Selection Types Selection inputs let users choose from a list of options: - **Checkbox** -- multiple selections with checkboxes. - **Radio** -- single selection with radio buttons. - **Single Select** -- dropdown for a single selection. - **Multi Select** -- dropdown for multiple selections. Each selection type has an **Options Type** dropdown with two values: **Static** or **Dynamic**. ### Static Options 1. Set **Options Type** to **Static**. 2. Click **Manage options** to open the editor and add rows. Each row has: - **Label** -- text shown to the user. Required. - **Value** -- value submitted when this option is selected. Required. 3. Use the editor's **Add Option** button to append rows; click **Save Options** to commit. Both Label and Value must be at least 1 character long. ### Dynamic Options 1. Set **Options Type** to **Dynamic**. 2. Fill the fields: - **Labels Delimiter** -- character used to split the resolved labels string. Default: `,`. - **Values Delimiter** -- character used to split the resolved values string. Default: `,`. - **Labels** -- Data Picker expression that resolves to the option labels. - **Values** -- Data Picker expression that resolves to the option values. A warning banner inside Block Settings reminds you that if your data contains the delimiter character, the options may be split incorrectly. --- ## Default Values Use the **Default Value** field to pre-fill the input. The field supports the Data Picker, so you can bind the default to any resource field or variable. Help text under the field changes per Type to describe what is expected (for example `YYYY-MM-DD format` for Date, `Coerced to a number` for Number). For selection inputs with **Static** options, the **Default Value** field gains a small swap button next to its label. The button toggles between two modes: - A **dropdown** of the static options (the selection's stored value is the option's `value`). - A **plain-text input** that supports template variables -- type the option's `value` directly, optionally as a Data Picker expression. For multi-value selections (Checkbox / Multi Select) separate values with commas. ## Labels and Help Text - **Label** -- text label displayed above the input field. - **Help text** -- smaller hint text shown below the input. Supports the Data Picker. - **Placeholder** -- hint text shown inside the empty input. Available on **Text**, **Textarea**, **Email**, **Number**, **URL**, **Single Select**, and **Multi Select** only -- Checkbox, Radio, Date, File, and Hidden inputs hide the Placeholder field. Supports the Data Picker. ## Validation Settings - **Required** -- toggle to make the field mandatory. Click the ⇄ button beside the label to take the value from data instead: see [Required from data](/docs/buttons/interface-button/interface-builder/how-to/forms/form-validation#required-from-data). Hidden inputs cannot be Required. - **Pattern** -- regex pattern for custom validation. Available on Text, Textarea, Email, Number, URL, and Date. Must be a valid regular expression. - **Pattern Error** -- custom error message shown when pattern validation fails. Only appears once Pattern has a value. - **Disabled** -- toggle to make the field read-only. A disabled field sends its **Default Value** and skips its validation. Click the ⇄ button beside the label to take the value from data instead; the same `true` / `yes` / `1` rule applies as for Required. Hidden inputs cannot be Disabled. For numeric bounds (**Min**, **Max**, **Min Error**, **Max Error**) and file size limits, see [Form Validation](/docs/buttons/interface-button/interface-builder/how-to/forms/form-validation). ## Style and Visibility The Input block uses the standard **Style** sub-tab (background, font, borders, radius) and **Visibility** sub-tab in Block Settings, the same as every other block. See [Block Styles](/docs/buttons/interface-button/interface-builder/how-to/layout/block-styles) and [Conditional Visibility](/docs/buttons/interface-button/interface-builder/how-to/visibility/conditional-visibility). --- # Using the Data Picker Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/data/data-picker.md This guide covers the everyday picker workflow. For the full breakdown of every tab, type filter, and badge — see the [Data Picker reference](/docs/buttons/interface-button/interface-builder/reference/data-binding/data-picker). ## Inserting Your First Placeholder 1. Click into any block setting that supports the Data Picker — for example a Title block's **Text** field. 2. The picker opens as a tooltip beside the field. 3. Pick the tab whose data you want (Deal, Organization, Person, User, Custom, Search Params, Variable, Functions, Context, or — inside a looping area — Loop item). 4. Click a field in the tree. A blue badge appears in the field as a single unit; the placeholder it represents (for example `{{deal.title}}`) is what gets resolved at render time. On a [floating window button](/docs/buttons/interface-button/interface-builder/explanation/floating-window-buttons) the **Deal**, **Organization** and **Person** tabs are not in the strip at all, because that button's views get no Pipedrive record. Builder view 'Data Picker Demo' with a Title block selected. The Block Settings sidebar's Text field shows a single blue 'Title' badge with a small × delete icon. The Data Picker tooltip is open beside the Block Settings panel: the Deal tab is selected (the dollar-sign tab) and the field tree below shows ID, Title, Creator (with an expand chevron), Value, Contact person, Organisation, Stage, Currency, Add time, Update time, Status, Probability. ## Combining Static Text and Placeholders You can mix plain text with badges in the same field. Type freely before, between, and after badges — the picker treats text as text and badges as atomic units. A typical Paragraph **Value** might read: ``` Deal: {{deal.title}} — {{deal.value}} {{deal.currency}} ``` At render time the three placeholders resolve to live values from the deal record (for example `Deal: Legendary 1995 — 3193 EUR`). ## Removing a Placeholder Three ways: - Click the small **×** on the badge. - Place the cursor after the badge and press **Backspace** — the whole badge disappears in one keystroke. - Select across the badge and type — the badge is replaced by whatever you type. ## Editing Complex Expressions in the Larger Dialog Once a field has more than one or two placeholders — or when you start mixing in functions like `if`, `formatCurrency`, or `daysBetween` — the inline picker gets cramped. Click the **expand** icon at the right edge of the Data Picker input to open the same field in a larger dialog. Toggle **Show result** to preview the rendered value (resolved against the active sample data) and **Show whitespace** to make spaces visible. For the **HTML** block specifically, **Show result** renders the compiled output as actual HTML (using the same sanitiser as the live view) so you can see the visual result without switching to Preview mode — see [How to Use the HTML Block](/docs/buttons/interface-button/interface-builder/how-to/blocks/html#previewing-without-leaving-the-dialog). Expand dialog open over the builder canvas. The dialog header reads 'Text' with a minimize icon top-right. A large Slate editor in the centre holds three placeholder badges separated by an em-dash and a space — Title, Value, Currency. Below it the Show result switch is on (showing the rendered preview 'Legendary 1995 — 3193 EUR' beneath the editor) and the Show whitespace switch is off. The Data Picker tooltip floats to the left of the dialog with the Deal tab selected. The dialog ignores clicks outside, so you can keep clicking around the canvas without losing your edits — only the minimize icon (top right) closes it. **Show whitespace** is useful when something looks "off" in the rendered output and you suspect a stray or missing space — for example a placeholder that touches the next word, or two spaces between values. Switch the toggle on to see every space in the field as a small dot. The toggle is a **global** preference that applies to every Data Picker field in the builder and is remembered across reloads, unlike **Show result** which is set per field. Expand dialog with the Show whitespace toggle on. The field contains plain text and small dot markers between every word, visualising each space character. Show result is also on; the resolved text appears below the editor. ## Working Inside a Looping Area When the field is inside an [area with looping enabled](/docs/buttons/interface-button/interface-builder/how-to/layout/areas#looping-an-area), the picker grows an extra **Loop item** tab (a repeat icon). Open it to: - pick a field of the current iteration's array item (the `index` field is shown last in the list) — placeholders resolve per repetition, so `{{deal.products.name}}` reads a different product on each loop; - pick `index` — the iteration number, starting at **1**. If the field is **not** inside a looping area, the Loop item tab does not appear. ## Type-Filtered Contexts Some block settings only accept a specific data type. The picker greys out fields that do not match: - **Table > Target Array** and **Area > Loop > Target array** accept only arrays. - **Visibility > Condition** accepts any value but is most useful with strings or booleans. - Most text-based settings exclude objects from the clickable set — clicking an object's badge only expands its children. You do not choose the filter manually — the surrounding setting decides it for you. ## Reusing the Last-Opened Tab The picker remembers which tab you opened last across fields. If you spend a session inserting Deal fields, the next picker you open also lands on the Deal tab. Switch tabs once and that becomes the new default. Useful when you are building a row of similar inputs. --- # Configuring an External Data Source Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/data/external-data-source.md ## Opening the URL Configuration Dialog 1. Open the **View settings** tab in the right panel. 2. Click the **Configure URL** button (next to **View URL**, with the active method shown as a `POST` / `GET` badge). The **URL Configuration** dialog opens. URL Configuration dialog open over the View URL demo view. The View end-point configuration card shows HTTP Method tabs (GET / POST, POST selected), an empty End-point URL field, the URL Active switch turned on, and the Omit oneclick metadata switch turned off. The Query Parameters card below has an Add Parameter button on the right and an empty state showing 'No query parameters configured' with an Add Your First Parameter button. The dialog is divided into cards, in this order: **View end-point configuration**, **Query Parameters**, and **Manage Headers**. Click **Save** in the top-right to apply changes, or **Cancel** to discard them. ## HTTP Method In the **View end-point configuration** card, pick **GET** or **POST** with the toggle buttons next to **HTTP Method** (default: **GET**). - **POST** -- sends a request body with deal/person/organization context. - **GET** -- appends parameters to the URL. ## End-point URL Enter the full URL of the external API endpoint in the **End-point URL** field. This is the URL the view calls to fetch data when it opens. The field supports the Data Picker, so you can build the URL from variables. ## URL Active Turn on the **URL Active** switch to enable the external data source. The helper text reads _"When disabled, no fetch will be made on view load."_ When off, no request is made and the **Custom** tab in the Data Picker remains empty. ## Omit oneclick metadata The **Omit oneclick metadata** switch tells Interface Builder not to add `event_id`, `resource_id`, or other OC-specific fields to the request body. Turn this on for APIs that reject unknown fields, such as the Pipedrive API v2. ## Query Parameters In the **Query Parameters** card, click **Add Parameter** (or **Add Your First Parameter** when the list is empty) to append a row. - Each row has a **Key** input and a **Value** input. Values support the Data Picker. - The **Trash** icon at the end of the row removes that parameter. - Keys must be 1--255 characters, values 1--512 characters. Duplicate keys are flagged with `Duplicate key not allowed`. ## Manage Headers In the **Manage Headers** card, click **Add Header** (the empty state shows _"No headers configured yet"_). Each header has: - **Key** -- the header name. Must contain only letters, numbers, and hyphens, cannot start or end with a hyphen, and cannot start with `x-oc-` (reserved for system headers). - **Value** -- the header value. Supports the Data Picker, so you can use dynamic values such as `{{variable.api_key}}`. :::note[OneClick-level headers are merged in automatically] If the OneClick button this interface is attached to has its **Headers** toggle enabled (configured outside the builder, on Pipedrive's **Edit a Button** page), every header listed there is sent with this request. You only need to set per-call headers here for values that differ between requests. See [OneClick-Level Headers](/docs/buttons/interface-button/interface-builder/explanation/architecture#oneclick-level-headers) for the merge order and the reserved `x-oc-*` keys. ::: ## Using the Data Once the URL is active, the external API response fields appear in the Data Picker under the **Custom** tab. 1. Open any Data Picker field. 2. Switch to the **Custom** tab. 3. Browse the response fields and click to insert chips that compile to placeholders like `{{custom.field_name}}`. The data is fetched at render time using the configured method, headers, and parameters. The response is parsed and made available as selectable fields. ## How the Response Reaches the View When the view opens, the builder calls your data source URL and then waits for your response. The view stays in a loading state until the response arrives, and renders as soon as it does. The total wait is capped at roughly **20 seconds**. If nothing arrives in that window, the user sees a `Request timed out. No custom data received.` toast. If the data source URL returns an HTTP status outside 2xx, the user sees `Data loading failed (status 500)` (or whichever status came back). For the exact request shape your endpoint receives — body, headers, system metadata — see the [View Data Source reference](/docs/buttons/interface-button/interface-builder/reference/data-binding/view-data-source). For the parallel-fetch state machine and the differences between Test, Preview, and live render, see [External Data Flow](/docs/buttons/interface-button/interface-builder/explanation/external-data-flow). ## Responding with a Message View Sometimes the "data" you have for the user is a message, not records -- the record cannot be found, the session expired, or a step is still missing. Return a message-view response instead of real data: ```json { "oneclick_data": { "error_message": { "title": "Account not found", "message": "We could not find that account. Choose another." } } } ``` The view shows a full-page message view with your title and message, plus **Go Back** and **Retry** buttons. Use this instead of a toast when the user cannot proceed -- they cannot miss a full-page card. The object form also accepts optional `hideRetry: true` and `hideBack: true` flags to hide the corresponding button. Full-page message view in the destructive variant: a light red card with a red circle-alert icon, the title Account not found, the message We could not find that account. Choose another., and the buttons Go Back (outlined) and Retry (solid red). If you only need a single-line message, use the string form. It gets the title "Error": ```json { "oneclick_data": { "error_message": "Something went wrong" } } ``` ### Lists and variants To list several items, send `message` as an array of strings. The message view shows them as a bullet list. Add `variant` to change the colours and icon -- `destructive` (default), `warning`, `info`, `success` or `default`: ```json { "oneclick_data": { "error_message": { "title": "A few things before we continue", "message": ["Add a delivery address", "Choose payment terms"], "variant": "info" } } } ``` Full-page message view in the info variant: a light blue card with a blue info icon, the title A few things before we continue, a bullet list with Add a delivery address and Choose payment terms, and the buttons Go Back (outlined) and Retry (solid blue). ### `message_view` for messages that are not errors When the message is not an error -- for example a `success` or `info` note -- send it as `message_view` instead of `error_message`. The fields and the view are the same; only the name is neutral. `message_view` takes the object form only: ```json { "oneclick_data": { "message_view": { "title": "Almost there", "message": "Customer created. Add a contact person and press Retry.", "variant": "success" } } } ``` Full-page message view in the success variant: a light green card with a green circle-check icon, the title Almost there, the message Customer created. Add a contact person and press Retry., and the buttons Go Back (outlined) and Retry (solid green). - `variant` changes the look only. The buttons stay **Go Back** and **Retry**, and the response is still not a success response. - A missing `variant` is `destructive`, as with `error_message`. - If a response carries both fields, `error_message` wins and `message_view` is ignored. Both fields support a small HTML subset in the message text. See the [Messages & Toasts reference](/docs/buttons/interface-button/interface-builder/reference/data-binding/messaging) for the allowed tags and link behaviour, and [HTTP Response Format → `message_view`](/docs/buttons/interface-button/interface-builder/reference/data-binding/http-response-format#message_view) for all rules. ## Responding with a Redirect If the data source should divert the user to another view instead of rendering, return a redirect: ```json { "oneclick_data": { "redirect_view": { "id": "target-view-id", "params": { "deal_id": "123" } } } } ``` The view shows a "Redirecting..." toast and navigates to the target view. If the target ID does not exist, the view falls back to a full-page message view with the message _"View with ID ... was not found"_. See [HTTP Response Format](/docs/buttons/interface-button/interface-builder/reference/data-binding/http-response-format) for the full list of accepted shapes. --- # Sending Messages and Toasts from Your Backend Source: https://help.theoneclick.io/docs/buttons/interface-button/interface-builder/how-to/data/messages-and-toasts.md Interface Builder shows user-visible messages in three places: 1. **Toast** — a short notification that pops up in a corner of the view. 2. **Inline alert** — a coloured box that replaces the form after submission. 3. **Full-page message view** — takes over the view and offers Retry / Go Back buttons. You decide which one appears by combining the button's settings with the shape of the response your API returns. ## Do I need `oneclick_data`? No — not for a plain toast. **A toast can come from several simpler shapes**; the `oneclick_data` envelope is only required when you want: - a **redirect** (navigate the user to another view) on a URL button or a form submit, or - a **full-page message view** (on a view data source or on a form submission error). For a plain toast — success or error — a top-level response with a `message` is enough. For URL buttons, even a plain text body (not JSON) works. ## Two-minute recipes Pick the row that matches your situation. | I want… | Button setup | Return from API | |---|---|---| | A success toast after form submit | Form Submit, **After submission = Wait for response** | `{ "message": "Saved." }` | | A coloured toast with a title | same | `{ "message": "Profile is up to date.", "title": "Saved", "variant": "success" }` | | Replace the form with a "thank you" screen | same + **Show message after submission** ON | same shape as above | | Navigate to another view after submit | Form Submit, **After submission = Wait for response** | `{ "view_id": "receipt-view" }` | | Show a toast, then navigate | same | `{ "oneclick_data": { "message": "Done.", "redirect_view": { "id": "receipt-view" } } }` | | Error toast on failed submit | same + **non-2xx** HTTP status | `{ "message": "Email already in use." }` | | Full-page error after failed submit (view with a data source) | same + **non-2xx** HTTP status | `{ "oneclick_data": { "error_message": { "title": "Blocked", "message": "…" } } }` | | Quick toast after URL button click | URL Button | plain string body: `"Added to cart"` — **or** `{ "message": "Added to cart" }` | | Redirect after URL button click | URL Button | `{ "oneclick_data": { "redirect_view": { "id": "next" } } }` | | Toast then redirect after URL button click | URL Button + **Wait page transition** ON | Stream interim toasts via the polling endpoint, then return `{ "oneclick_data": { "redirect_view": { "id": "next" } } }`. URL buttons drop a sibling `message` next to `redirect_view`. | | Full-page error on view data source | View with a data source | `{ "oneclick_data": { "error_message": { "title": "…", "message": "…" } } }` | The rest of the page explains each case in detail. --- ## Form submit responses For form submits the submit button's **After submission** setting decides what the builder does with your response. ### After submission = Wait for response All the shapes below are accepted. Return the simplest one that fits. **Just a toast** — return a JSON body: ```json { "message": "Profile saved" } ``` **Coloured toast** — add a variant: ```json { "message": "Profile saved", "variant": "success" } ``` `variant` can be `default`, `destructive`, `info`, `success`, or `warning`. **Toast with a title** — add a title: ```json { "message": "Profile is up to date.", "title": "Saved", "variant": "success" } ``` - With **Show message after submission** off → shown as a toast where `title` is the bold first line and `message` is the description. - With **Show message after submission** on → the form is replaced by an inline alert containing the title and message. The view scrolls to it automatically. **Just a navigation** — no message, just send the user to another view: ```json { "view_id": "target-view" } ``` **Toast plus navigation** — return the `oneclick_data` envelope. This is the only shape that carries both: ```json { "oneclick_data": { "message": "Saved.", "redirect_view": { "id": "receipt", "params": { "order_id": "4321" } } } } ``` ### After submission = Select view The button navigates on its own once the server replies. You usually need no body at all — HTTP 2xx is enough. If you want a toast to flash just before the navigation, return one of these: ```json { "message": "Saved." } ``` ```json { "success": "Saved." } ``` ```json { "oneclick_data": { "message": "Saved." } } ``` All three produce a success toast and then the navigation. ### Submit errors Return any non-2xx HTTP status. The accepted bodies are: | Body | What the user sees | |---|---| | `{ "message": "…" }` | Error toast with the message | | `{ "oneclick_data": { "message": "…" } }` | Error toast with the message, plus a trailing "Something went wrong" toast (the body has no top-level `message`, so the unconditional fallback toast also fires) | | `{ "oneclick_data": { "message": "…", "redirect_view": {…} } }` | Error toast, then navigation | | `{ "oneclick_data": { "error_message": "…" } }` | Full-page message view replaces the view, plus a trailing "Something went wrong" toast in the corner | | `{ "oneclick_data": { "error_message": { "title": "…", "message": "…", "hideRetry": false, "hideBack": false } } }` | Full-page message view with your title and message, plus a trailing "Something went wrong" toast in the corner | | Anything else | Generic "Something went wrong" toast | The submit button re-enables on error unless you turned on **Disable form after submission**. --- ## URL button responses URL buttons accept any of these. Two of the shapes only render their toast when **Wait page transition** is enabled on the button — see [URL button quirks](#url-button-quirks) below. **A plain text body** (not JSON) — shortest path: ``` "Added to cart" ``` Shown as a success toast. You may include inline HTML inside the string (see [HTML support](#html-support)). **JSON with a top-level `message`** — still no envelope needed: ```json { "message": "Added to cart" } ``` Also shown as a success toast. **Envelope with a message**: ```json { "oneclick_data": { "message": "Added to cart" } } ``` Renders a success toast **only when Wait page transition is on**. If the button does not use Wait page transition (the default), this body is silently dropped — the user sees no toast. Prefer the top-level `{ "message": "…" }` shape for plain toasts and reach for the envelope only when you also need a redirect or are already streaming interim updates through the polling endpoint. **Envelope with a redirect** — the envelope is *required* for this: ```json { "oneclick_data": { "redirect_view": { "id": "receipt-view", "params": { "order_id": "4321" } } } } ``` Silent navigation. **Envelope with both** — only the redirect runs: ```json { "oneclick_data": { "message": "Payment successful", "redirect_view": { "id": "receipt-view" } } } ``` URL buttons navigate as soon as a `redirect_view` is present and **silently drop** the sibling `message`. To show a message and then navigate, enable **Wait page transition** on the button and stream the toast through the polling endpoint before returning the final response with `redirect_view`. (Form submits behave differently — they show both the toast and then navigate; see [Form submit responses](#form-submit-responses).) **Errors**: any non-2xx status becomes an error toast. The message comes from the body if it is a plain string or a `{ "message": "…" }` object; otherwise the generic failure message is shown. The button re-enables so the user can try again. ### URL button quirks URL buttons handle the response in two stages: an immediate handler for the very first response, plus an optional polling loop that runs only when **Wait page transition** is on. Because of that split, the envelope `{ "oneclick_data": { "message": "…" } }` only surfaces in the polling-aware path: - **Wait page transition off** (the default): only the immediate handler runs. Plain string bodies and top-level `{ "message": "…" }` produce a toast; envelope-only `oneclick_data.message` is silently dropped. - **Wait page transition on**: the button polls for interim updates (each one becomes a `toast.info`) and at the end shows the final response's `oneclick_data.message` as a `toast.success`. If your final (immediate) response carries both a `message` and a `redirect_view`, the message is dropped — only the redirect runs. Polled responses can carry both, in which case the polled message still shows as `toast.info` just before the redirect. URL buttons never render `title` or `variant` — the toast is always a success toast (or, on errors, an error toast). Those fields only take effect on form submits. --- ## View data source error When a view has a data source URL, the response fills the Data Picker's Custom tab. If you need to show an error instead of data — for example "Account not found" — return this shape (and the envelope **is** required): ```json { "oneclick_data": { "error_message": { "title": "Account not found", "message": "We could not find that account. Choose another." } } } ``` The view shows a full-page message view with your title and message plus **Retry** and **Go Back** buttons. Add `"hideRetry": true` or `"hideBack": true` to hide either button. Full-page message view in the destructive variant: a light red card with a red circle-alert icon, the title Account not found, the message We could not find that account. Choose another., and the buttons Go Back (outlined) and Retry (solid red). To list several things the user must fix, send `message` as an array of strings. The message view shows them as a bullet list. Add `variant` to change the colours and icon of the message view — `destructive` (default), `warning`, `info`, `success` or `default`: ```json { "oneclick_data": { "error_message": { "title": "A few things before we continue", "message": ["Add a delivery address", "Choose payment terms"], "variant": "info" } } } ``` `variant` changes the look only. The buttons stay **Go Back** and **Retry**, and the response still counts as an error. Full-page message view in the info variant: a light blue card with a blue info icon, the title A few things before we continue, a bullet list with Add a delivery address and Choose payment terms, and the buttons Go Back (outlined) and Retry (solid blue). When the message view is not an error, send it as `message_view` instead of `error_message`. The fields and the view are the same; the name just reads better for a `success` or `info` note. `message_view` takes the object form only: ```json { "oneclick_data": { "message_view": { "title": "Almost there", "message": "Customer created. Add a contact person and press Retry.", "variant": "success" } } } ``` Full-page message view in the success variant: a light green card with a green circle-check icon, the title Almost there, the message Customer created. Add a contact person and press Retry., and the buttons Go Back (outlined) and Retry (solid green). If you only need a single-line message, the string form also works: ```json { "oneclick_data": { "error_message": "Something went wrong" } } ``` The same message view also appears when a form submit on this view returns `oneclick_data.error_message` or `oneclick_data.message_view`. --- ## title and variant belong at the top level :::caution[Common mistake] The `oneclick_data` envelope **does not carry `title` or `variant`** — its allowed fields are only `message`, `redirect_view`, `error_message`, `message_view`, and `event_id`. Putting `title` or `variant` inside `oneclick_data` is silently ignored. (The `variant` inside the `error_message` or `message_view` object is a different field: it sets the look of the full-page message view.) ::: If you write: ```json { "oneclick_data": { "message": "Done", "title": "Saved", "variant": "success" } } ``` the `title` and `variant` are silently ignored. Put them at the top level instead: ```json { "message": "Done", "title": "Saved", "variant": "success" } ``` :::caution[URL-button toasts ignore title and variant] This top-level shape is only read on form submits with **Wait for response**. URL buttons do not support titles or variants — the toast always renders as a success toast regardless. ::: --- ## HTML support Every `message` and `title` — whether at the top level or inside `oneclick_data` — passes through a narrow HTML allowlist before rendering. You can use a small subset: ``` / bold / italic underline
line break inline monospace link (opens in a new tab)

paragraph

generic wrapper