> For the complete documentation index, see [llms.txt](https://docs.rewst.help/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rewst.help/rewst-documentation/documentation/apps/blocks.md).

# Blocks

## What are blocks?&#x20;

In Rewst's App Builder, *blocks* are the building components that enable users to rapidly create and customize their apps. Each block is designed to fulfill a specific function; from basic navigation to data visualization, allowing the construction of robust and user-friendly pages.&#x20;

Blocks are grouped into logical categories based on their primary functions, making it easier to identify and choose the right ones for a given task. When the Rewst Agent builds your App Builder app, it will place the required blocks onto the Canvas for you. Each block can be fine-tuned with various settings to meet unique requirements.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2F7mS7qdsOIfd4iyPOOej4%2FScreenshot%202026-07-29%20at%203.22.23%E2%80%AFPM.png?alt=media&amp;token=2b01c619-3cf1-4526-8780-628c0de686e0" alt=""><figcaption><p>The block library of the App Builder Canvas</p></figcaption></figure>

Click **Blocks** in the left side menu of your App Builder Canvas to expose the total block library. Add any block to the Canvas by clicking on it in the library, dragging it, and dropping it onto the Canvas. Then, click on that block on the Canvas to open its configuration settings and expand the hidden right side menu. Each block will have its own unique configuration fields.

## App block guidance

{% hint style="success" %}
Click on any of the block types below to expand and see information about its setup and purpose. For more on binding related to blocks and pages, see our documentation [here](/rewst-documentation/documentation/apps/app-pages.md#binding-in-apps).&#x20;
{% endhint %}

### Navigation

<details>

<summary>Nav Links block</summary>

The **Nav Links** block drops in a horizontal row of clickable text links via a menu bar. It auto-populates with two placeholder links: "Home" and "Link." It keeps any included links evenly spaced.&#x20;

**Additional configurations**

* **Link spacing** - Change the gap between links, applied to both on the Canvas while designing and in the live app
  * **Compact**
  * **Standard**
  * **Relaxed**
* **Use authored nav styles** checkbox&#x20;
  * If off, Rewst applies its standard nav look
  * If on, Rewst keeps whatever custom styling you have set
* **Items binding** - switch from static to automatic links, useful for different links for different customers or a menu driven by data a workflow produces
  * **Label** - the text people see
  * **Link URL** - where it goes
  * **Open in new tab** - set on or off

</details>

<details>

<summary>Vertical Nav block</summary>

The Vertical Nav block offers a stacked column of navigation items, each with an icon next to its label. This is the classic left-hand menu you'd see down the side of an app. It arrives with three pre-populated items: Home, Dashboard, and Settings. Each already has its own assigned icon. Unlike the Nav Links block, this block doesn't have an open in new tab option.

**Additional configurations**

* **Show icons** - on by default, but if turned off results in a plain stacked text menu without icons
* **Navigation color** - the color applies to the text and icons in their hover and active states, not the resting color
  * **Gray**
  * **Black**
  * **Primary**
  * **Secondary**
  * **Tertiary**
* **Use authored nav styles** checkbox
  * If off, Rewst applies its standard nav look
  * If on, Rewst keeps whatever custom styling you have set

**Per-item settings**

* **Icon** - the icon picker chooses from a large built-in icon set
* **Link URL** - where it goes
* **ID&#x20;*****-*** an identifier for the item[<br>](https://docs.rewst.help/documentation/app-builder/components/row)

</details>

<details>

<summary>Icon Nav block</summary>

**Icon Nav** is the most compact of the three navigation blocks: a horizontal row of icon-only buttons with no visible text at all. Think of the cluster of small icons you'd see in the top-right corner of an app header — a profile icon, a notification bell, a logout arrow. It comes with two pre-populated items: Profile and Logout. Text is genuinely not a part of this block; it shows icons only. There is no label functionality. If you swap an item's icon, the built-in description doesn't follow, and the description changes to whatever new icon you choose.

**Additional configurations**

* **Icon color** - icons will maintain their grayscale filter with reduced opacity, while he selected color tint will be applied on hover and active states
  * **Gray**
  * **Primary**
  * **Secondary**
  * **Tertiary**

**Per-item settings**

* **Icon** - the icon picker chooses from a large built-in icon set
* **Link URL** - where it goes
* **ID&#x20;*****-*** an identifier for the item

</details>

### Layout

<details>

<summary>Container block</summary>

The **Container** block is the layout wrapper block, a structural block that holds other components rather than rendering data itself. It p**rovides the responsive layout context for its children.** Blocks are meant to live inside a Container.&#x20;

Use the container block to group content into a page region, such as a tall chart in a wide cell beside a narrow cell that stacks other smaller metric blocks. It's not a data component; it has no data source, columns, or value binding of its own.

</details>

<details>

<summary>Row block</summary>

The **Row** block is the horizontal layout block. It takes a slice of the page's vertical stack and divides that width among its cells. Alignment for rows works as follows:

* Split width across its cells. By default the split is equal: N cells = N equal fractions. Give a cell a weight of 1–6 to get a ratio instead — weights of 2 and 1 produce a two-thirds / one-third layout.
* Each cell fills 100% of its slot, so a component inside a cell stretches to that cell's width rather than sizing to its content.
* Cells can nest another row. That's how you build asymmetric structure — for example a tall chart in a weight-2 cell next to a weight-1 cell that nests a vertical stack of small metric tiles.
* It's purely structural. Like Container, a row renders no data of its own; it only positions the metric, chart, table, text, button, and form blocks placed in it.
* Keep roughly 3–4 items per row. Past that, cells get too narrow to stay readable.
* A 3-cell row stacked over a 4-cell row won't line up, since the fractions differ. Use the same cell count across stacked rows, or use explicit cell weights, when you want columns to align vertically.

Use the Row component to align multiple elements, such as buttons, images, or text, within a single horizontal line, or create a base for grid systems that require precise control over the placement and alignment of components.

</details>

### Content

<details>

<summary>Heading block</summary>

The **Heading** block is the titling block. It accepts an optional subtitle for supporting copy above or below the title, and carries a right-alighed actions slot in the heder bar. The Heading block you manually drag onto the Canvas is a plain heading with no level, subtitle, or actions slot. The page header with subtitle and a filter control in the actions slot is something the Rewst Agent builds when it lays out a page.&#x20;

The heading can be used on lower hierarchy levels to act as section headings inside the page body, labeling a row, a cell, or a region so each area of the surface announces its job. It does not carry data of its own, nor does it create a layout.

</details>

<details>

<summary>Text block</summary>

The **Text block** is a paragraph and prose element as opposed to a data component. Where other content blocks each render a specific structure, Text renders only words: descriptions, helper copy, instructions, captions, a sentence of context under a chart.

It's distinct from the Heading block — a level-1 heading compiles to the actual page header, but Text has no such structure. It's regular prose in the flow of the page.

Text blocks work for both fixed copy and dynamic values. To create dynamic text, bind it with `data-binding-text` pointing at a proved CTX path, e.g. `data-binding-text="CTX.population.population_formatted"`

{% hint style="warning" %}
Typing `{{ CTX.value }}` directly into the text content doesn't interpolate. It renders literally on the page as those characters. Dynamic text has to go through `data-binding-text`.
{% endhint %}

Text blocks have no fallback logic, filters, or loops when you bind them. Keep the bound path direct and shape the value in the workflow output or data source instead.&#x20;

Use the text block for displaying informative content like service descriptions, company info, or user guides. Try it in its dynamic form to show changing text content such as user names, statuses, or other personalized information.&#x20;

</details>

<details>

<summary>Image block</summary>

The **Image** block puts a picture on the page. Drag the block onto the Page Builder Canvas, then double click on the placed block to open the image picker. From there you can upload a new image, pick one already in the app's image library, or remove a stored image.\
\
![](https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2F1oRxCKCoJh7KryeNWx4W%2FScreenshot%202026-09-03%20at%202.46.51%E2%80%AFPM.png?alt=media\&token=bd9ea3ee-9dbb-4e36-81a4-94e683917da3)

Images you upload are stored by Rewst and referenced by the app, so the library is shared across the app's pages only, not across all apps. The Image block has no runtime renderer behind it. It's ordinary markup, which means it's dynamic only if you [bind](/rewst-documentation/documentation/apps/app-pages.md#binding-in-apps) it.

| Need                    | Attribute                            |
| ----------------------- | ------------------------------------ |
| Image source from data  | `data-binding-src`                   |
| Alt text from data      | `data-binding-alt`                   |
| Show/hide conditionally | `data-binding-visible="{{ CTX.x }}"` |

Use the Image block to insert images that don't fit other block usees. For a customer logo, use the Brand logo block. For a glyph, use the Icon block.&#x20;

</details>

<details>

<summary>Brand Logo block</summary>

The **Brand Logo** block shows the viewer's own company logo. It's the multi-tenant version of the Image block. An Image block shows the same picture to everybody. Brand logo asks at page load: *who's looking at this, which organization do they belong to, and what logo is on file for them?* Then, it renders the correct one.

It has four states that cascade based on what's actually filled in on that organization's branding profile, so a customer who never sent you a logo file still gets something sensible rather than a broken image icon:

1. **Image** — the uploaded logo, if there is one
2. **Wordmark** — the company name as styled text
3. **Initials** — an initials mark
4. **Empty** — nothing, cleanly

Branding only resolves for a viewer who is signed in and identified as belonging to an organization. Anonymous viewers of a public app, and anyone opening a share link, are never resolved to an organization. Instead, they skip customer branding entirely and get the fallback.

The block renders a real logo only when both are true:

* The app has customer branding turned on
  * **Global** tab > **Appearance** > **Use customer branding**
* The organization has branding filled in
  * **Global > Appearance > Use customer branding >** **Manage branding** > pick the organization > logo, colors, favicon > **Save branding**

Per-organization branding edits take effect immediately. The app-level toggle doesn't. Viewers read it out of the published snapshot, so it doesn't reach anyone until the next time you click **Publish App**.

{% hint style="warning" %}
Style the outer wrapper only. Don't write app CSS targeting the block's inner pieces — it fights the component, and a known side effect is the fallback wordmark leaking into view when it shouldn't. To change the logo's size, set it in the branding profile rather than in CSS.
{% endhint %}

</details>

<details>

<summary>Icon block</summary>

The **Icon** block allows you to integrate visual content into your web applications. Choose from 18 curated icons in the picker, plusa. custom field where you can type and [Lucide icon](https://lucide.dev/) name, HTML, or emojis.

Use the Icon block to showcasing product features or service details, enhance blog posts or articles with relevant visuals, or display logos or other branding materials to strengthen identity in your app.

</details>

### Data&#x20;

<details>

<summary>Metric Card block</summary>

The **Metric Card** block is a solid colored card showing one value with a title. It's the "what do I need to know before I scroll" element for a page. This is the simplest of the data blocks. A metric card should stay a summary tile — a number, a color, maybe an icon, a delta, or a small trend cue. Once you find yourself wanting a breakdown, a comparison, or multiple related figures inside one card, that should be a chart or table block in its own section.&#x20;

Because the page is a vertical stack of rows and a row divides its width across cells, metrics conventionally sit as a row of three or four across the top of a dashboard. They also nest well: a narrow cell holding a vertical stack of small metrics beside a wider cell with a tall chart reads nicely, and keeps the row widths aligned with whatever sits below.

Note that the number should arrive pre-computed from the workflow. Metrics bind to a scalar in CTX, so the aggregation — counting, summing, filtering to a subset — belongs upstream in the workflow's transform nodes, not in the page.

**Additional configurations**

* **Title**
* **Label**
* **Value**
* **Subtitle**
* **Prefix/Suffix**
* **Icon**
* **Color**
* **Variant**
* **Footer** - Use the footer text for comparison text, for example `+12% from last month`

</details>

<details>

<summary>Data Table block</summary>

The data table component allows you to display and manage rows of data in a structured, tabular format. This component is essential for MSPs to handle large datasets efficiently, such as client information, service logs, or performance metrics, providing a clear and interactive view of data.

It renders rows from an array in CTX, with explicitly declared columns. If you declare no columns, the table auto-detects them from the data at runtime. Otherwise, you can manually declare each column and how it should render. Empty cells show `-`.&#x20;

Use it to display detailed lists of customer tickets and their statuses, manage inventory levels across multiple client sites, showcase performance reports with sortable metrics, or organize billing and transaction records for easy access and analysis.

**Additional configurations**

* Choose the **Data Source** from the drop-down selector in the field.
* Enter optional **Static Data (JSON)** into the code field.&#x20;
* Click **+** or **Auto-detect** to add your table's columns.
* Use the **Table Options** menu to choose if your table will have **Sortable columns**, **Show search box**, **Show refresh button**, and a pre-set number of **Rows per page**.
* Search, per-column sort, per-column filtering, pagination, refresh, and row-click are all declarative flags included in the block rather than code you write. You can also set `defaultSortColumn` and `defaultSortDirection`.

</details>

<details>

<summary>Bar Chart block</summary>

The **Bar Chart** block allows you to create a representation of data and display it in your page. It encodes values as length along a categorical axis, and that makes it the most accurate of the shapes for comparison. It best answers the question "which of these is biggest, and by how much?"

Use the bar chart block whenever you have more than five categories, or whenever the precise magnitudes matter more than the part-to-whole story. It's great for when the buckets are discrete and unordered, such as ticket counts per technician or endpoints per OS. While a line chart implies a progression between adjacent points, bar doesn't. The layout allows for long category labels. Ask the Rewst Agent to convert the block to horizontal bars. It also supports multiple series, so grouped bars work for comparing the same categories across two dimensions — this month vs. last month per queue, for instance — with the legend distinguishing them.

The bar chart isn't suitable for a genuine time series with many points.&#x20;

</details>

<details>

<summary>Line Chart block</summary>

The **Line Chart** block generates a chart with plotted points connected along an ordered axis, plus a title and optional legend. Line answers "how did this move across a sequence?" with the answer almost always being time. The line chart can plot several lines on shared axes to compare trends against each other. It reads a continuous axis. The horizontal position carries meaning, so gaps and slopes are information, not decoration.

Data binding works the same way as every other data component: it reads a series from CTX, usually landed there by a workflow-backed data source, and re-draws when that CTX value changes. You never need to redraw the chart

Use the line chart to display ticket volume per day, endpoint check-ins over a week, storage growth per month, SLA breach trend, or anything where the question is "is this getting better or worse?" It's not a good fit for unordered categories — connecting "Windows → macOS → Linux" with a line implies a progression that doesn't exist.

</details>

<details>

<summary>Pie Chart block</summary>

The **Pie Chart** block will create a pie chart representation of data and display it in your page. Pie aims to answer exactly one question: what's the composition of this whole? Donut is a chart-type option for this block.

Use the pie chart to display tickets by priority, endpoints by OS, licenses assigned vs. available, or spend by category. It's a poor fit for anything over 5-6 categories, anything that changes over time, or comparing magnitudes precisely.

Like every other data component, it's bound to CTX, not to hardcoded numbers: you point it at an array/series in CTX, which typically arrives from a workflow-backed data source. When that CTX value changes — a page filter re-runs the workflow, an interaction sets new state — the chart re-draws itself. You never redraw it manually.

</details>

<details>

<summary>For Each block</summary>

The **For Each** block is App Builder's repeater primitive (`app-repeater`). It renders its child markup once per item in an array you bind to it, so you can build custom repeated layouts like card grids, list rows, tiles, etc., instead of a fixed table. Because it binds to CTX, it's reactive: when the array in CTX changes — a workflow data source returns new rows, a filter re-runs the query — the repeated output re-renders automatically, no loop logic required.

Use For Each when the repeated thing isn't a table row: cards, tiles, avatar lists, custom-styled feed items, anything where you control the markup per item. Use a table block instead for genuinely tabular records

</details>

### Actions

<details>

<summary>Button block</summary>

Unlike Metric Card or Data Table, which have real configuration behind them and render themselves from data, the **Button** block has no configuration and no engine behind it. It's a styled, clickable shape. The behavior is a separate thing you attach. Double click on the button on the Canvas after it's been placed to edit the button text.

Use the Button block to submit forms and collect user inputs, redirect users to other sections of the app or external resources, or initiate downloads or transactions. You can also chain the button's actions together: run a workflow, wait for it to finish, then refresh the table so the new record appears. \
\
Don't choose a plain Button when a specialized one exists. The rest of the blocks in this category come pre-wired, and save you steps. See the documentation for each to learn more about their specific usecases.&#x20;

Built-in actions for the Button block are:

* Run workflow + store result
* Refresh data source
* Toggle CTX boolean
* Row click detail
* Open/close sideout
* Save edit surface
* Set status
* Get last run

</details>

<details>

<summary>Refresh Button block</summary>

The **Refresh Button** block has real configuration compared to the Button block: you point it at a target element by ID, and give it a label and a style. On click, it animates and pokes that target. It does not itself re-fetch data. The target has to be listening for it. Pointing it at an ID that doesn't exist fails quietly — it just logs a warning and does nothing.

</details>

<details>

<summary>PDF Export block</summary>

The **PDF Export** block is a "Download report" button with genuine configuration options:

* Page size
* Portrait/landscape
* Margins
* Density
* Watermark
* Branding text
* Hide app shell in output

Use the preview in the Page Builder to see what your PDF will look like to your end user, and update its appearance using the configuration fields.

</details>

<details>

<summary>Link block</summary>

If the only job is direct the user to go somewhere, the **Link** block is simpler than setting up a button, and behaves like a real link: middle-click, open in new tab. There's also a back-link style for return navigation. Double click on the block once placed on the Canvas to edit the link address, as well as font styling for italics, underlining, and strikethrough.

</details>

<details>

<summary>Agent Chat block</summary>

The **Agent Chat** block drops a working Rewst Agent conversation directly onto an app page, so someone using your app can ask an agent for help without leaving it. You're not building an agent in App Builder. You're placing a window onto an agent that already exists in your organization. The sequence is to build and configure the agent first, then point this block at it. Leave the agent unset and the block renders a `not configured` state rather than breaking the page.

The block starts as a placeholder. On page load, the app runtime swaps it for the real chat interface — a proper authenticated chat window served from Rewst itself, not a third-party embed. At that moment Rewst re-validates the agent against whoever is actually looking, **n**ot against you, the builder. The viewer's own identity and organization are checked before the chat is handed over. Placing the block on a page isn't a way to lend out access.

{% hint style="warning" %}
Agent Chat is signed-in only in its current version. Viewers who are signed in and not using a share link get the chat. Public viewers and anyone opening a share link get an unavailable state instead. If you're building a portal that customers reach by share link, or a public-facing page, this block won't work for them.
{% endhint %}

</details>

## Configuration menus for blocks

Click on any block once it's placed on the Page Builder Canvas to open its configuration settings in the right side of your screen.&#x20;

### Properties

* **Traits**
  * Add Binding for your block, in conjunction with [interactions](#actions-1)
  * Enter the **ID**&#x20;
  * **Add Class**
  * **Title**
  * **Display Condition**
* **Styles**
  * **General** contains settings for layout plumbing: whether an element stacks, sits inline, or gets pulled out of the normal flow and pinned somewhere. Most pages never need to touch it.
  * **Dimension** is where you'll spend most of your time.

    * **Padding** - space inside the element, between its edge and its content. More padding on a card means a roomier card.
    * **Margin** - space outside the element, pushing neighbors away. More margin means more gap between cards.

    Nearly every visual spacing problem is caused by one of those two. If the content is squeezed against the edge, that's padding. If two things are jammed together, that's margin.
  * **Typography** contains settings for text appearance — font, size, weight, color, alignment — plus line height, which controls the space between lines of text. Line height is usually the single fastest way to make a dense paragraph readable.
  * **Decorations** contains settings for background color, borders, corner rounding, drop shadows, and transparency. This is where a plain box becomes a card. Rounded corners plus a soft shadow is most of what makes something read as "a card" rather than "a rectangle."
  * **Extra** is the optional polish menu. Transitions make a change happen smoothly over time instead of snapping — that's what makes a hover effect feel nice rather than jumpy. Transforms rotate, scale, or skew an element. This section is for refining and optional for use in your page.

### Config

* **Set visibility** is the optional conditional show/hide control for the block in question. You point it at a true/false value in the page's data, and the block element appears when that value is true and disappears when it's false.
  * It's a binding, except that instead of controlling what an element says, it controls whether it shows up at all.
  * Content inside a hidden panel still gets checked when you publish. A detail panel that starts closed still needs its fields wired to real, valid data.
  * Example uses:
    * Empty states: "No results found" appears only when there are no results
    * Detail panels: the side panel stays hidden until someone clicks a row
    * Result messages: a success or error notice appears only after an action runs
    * Situational sections: content that only makes sense for certain statuses
* Additional configuration fields will appear and differentiate for each block type. If you're unsure what any of them mean, ask the Rewst Agent.

### Actions

Click **+ Add Interaction** to open the **Interactions** dialog. ***Interactions*** is where you answer the question *"and then what happens?"* Bindings put data *onto* the screen. Interactions are how the page responds to the person using it. Triggers for the interaction are:

* Page load
* Click
* Row click
* Mount
* Change
* Input
* Submit
* Keydown

{% hint style="info" %}
While Rewst allows you add to and edit this configuration manually, we recommend you let the Rewst Agent handle it as part of building your app on your behalf.
{% endhint %}

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FthkzTlYhlsyqqeWTCaU6%2FScreenshot%202026-09-03%20at%203.50.52%E2%80%AFPM.png?alt=media&amp;token=480d09ab-2730-4ff7-ae27-41a731351921" alt=""><figcaption></figcaption></figure>

* Attach structured behavior to page components.&#x20;
* Use the built-in actions. Advanced script is an escape hatch for custom JavaScript and can run real workflows, but with side effects
* Use scripts only for advanced post-readback behavior. Advanced scripts can run real workflows with side effects.

  <br>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

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

```
GET https://docs.rewst.help/rewst-documentation/documentation/apps/blocks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

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