---
title: Build Data Views from your tables
tag: verdalia-data-views
summary: >-
  Turn a table's rows into focused tables, cards, and checklists on your
  Pegboards.
---

# Build Data Views from your tables

A Data View turns the rows of one table into a focused table, card list, or checklist. Add it to a
Pegboard when you want the same structured state presented for a particular purpose: a watchlist,
project overview, review queue, or compact feed. To plot those rows instead, the Chart widget is a
separate thing with its own guide.

A useful mental model is:

```text
Workflow → Table → Data View → Pegboard
```

The workflow keeps the data current. The table declares what one row is, what each column means, and
holds the rows. The Data View chooses which rows to read and how they should look. The Pegboard
places that view alongside the rest of your system.

## Start with the table

Every Data View reads one table. Its declared columns become the choices available when you configure
columns, card templates, filters, and ordering — and their kinds decide which presentations and axes
are offered.

| Information | Column kind |
|-------------|-------------|
| Names, labels, URLs, icons | Text |
| A status from a fixed set | Select |
| Counts and whole quantities | Integer |
| Amounts, scores, percentages | Decimal |
| Yes/no state | Boolean |
| Calendar days | Date |
| Exact timestamps | Date and time |

Declare columns around facts you want to keep, not around one temporary visual treatment. A Select
column is worth preferring over Text anywhere you will filter or group by it, because its options are
fixed and cannot drift into three spellings of the same status.

A JSON column is where an API-shaped payload belongs, and it is not a useful view column: it renders
as structured data, and nothing inside it can be filtered, ordered, or grouped. Pull the handful of
values a view reads into columns of their own and leave the rest as JSON.

Rows also expose their `id`. For data synchronized from another system, use stable string IDs and
have the workflow upsert the same rows on later runs.

If the table is a log of readings — one sleep measurement per night, one metric sample per minute —
the view worth building is not over that table. Have a workflow aggregate it into a table whose rows
*are* what you want to look at, and point the Data View at that.

## Add and configure a Data View

1. Open a Pegboard and add a **Data View** widget.
2. Open **Edit widget** from its context menu.
3. Choose the source **Table**.
4. Optionally add search, filters, ordering, a result limit, or an offset.
5. Choose a View Type: Table, Card, or Checklist.
6. Bind the columns required by that presentation.

Search and filters decide which rows qualify. Ordering decides which come first. Limit and offset
select the returned window. A Data View reads at most 100 rows, so make sure the query window
contains the records your view needs.

A filter offers only the comparisons its column's declared kind can answer, which is the same
principle running through the whole system: the declaration decides what is possible. A date gets the
orderings, text gets **Contains**, and a select gets its own options to choose from rather than a box
to type into. A list column is the interesting case, because a list is not compared — it is asked
what it holds. **Includes** matches a row whose list holds the value you name, so a Tags column
filtered on `urgent` finds the rows carrying that tag. Where a filter takes several values —
**Includes any of** for a list, **Is any of** and **Is none of** for a single-valued column — the
values collect as chips, and a row qualifies on any one of them. That is how you build the view that
shows only what is `todo` or `doing` without building two views.

A row that does not satisfy the declaration renders in place with the reason it is broken and its raw
values, rather than being dropped or blanking the view, and can be corrected there.

The **Columns** section in the settings lists what the table declares — every column, its kind, and
how many options or nested columns a compound one holds. It is there to read while you bind, so the
names you type into a text slot match what the table actually calls them.

## Table View

Use Table when comparison and detail matter. Select the columns to show, choose one primary column,
and assign presentations such as text, number, date, boolean, link, status, tags, structured data,
or code.

A project watchlist might use:

| Column | Kind | Use |
|--------|------|-----|
| `title` | Text | Primary column |
| `status` | Select | Status presentation and filtering |
| `priority` | Integer | Sorting and comparison |
| `updated_at` | Date and time | Recency |
| `url` | Text | Link to the source |

## Card View

Use Card for a compact list of recognizable rows. Each row becomes a card with an icon, title,
description, color, and an optional destination.

Every one of those five is set in one of two ways:

- **Column** picks one of the table's columns from a dropdown. The card shows that column.
- **Text** writes a template that can combine several columns. It reads well but cannot be edited
  from the card, because there is no way to tell which part of the finished line came from which
  column.

With **Can edit** on, a Title or Description set to Column can be typed into straight on the board.
Click the text, change it, and press Enter or click away to save it; Escape puts it back. Icon, Color,
and URL still show what they hold rather than becoming fields. If neither Title nor Description is a
Column, nothing on the cards can be edited, and the settings say so under **Can edit**.

Reach for Column whenever one column is what the slot shows. Text is for when you want to combine.

Text slots use exact tokens:

```text
Icon:        {{ icon }}
Title:       {{ title }}
Description: {{ summary }}
Color:       {{ color }}
URL:         {{ url }}
```

Tokens insert the row's exact column value. They do not evaluate expressions, property paths, or
HTML.

Prepare values in the table before displaying them:

- Icons are either an Iconify identifier such as `ph:bookmark`, or a single emoji such as 🥛. Emoji
  are worth reaching for wherever the icon sets run out — groceries, food, travel — and work the
  same way in a Column or a Text slot, so a row storing 🍌 in its icon column draws 🍌. For one icon
  on every card, the button beside the Icon slot opens a picker with Phosphor icons and emoji.
- Colors can be `neutral`, `accent`, `info`, `positive`, `warning`, `critical`, or a valid hex color. The
  six names describe meaning rather than a shade, so they keep reading correctly in either theme; a hex
  does not.
- Destinations must be absolute `http://` or `https://` URLs.

Invalid values fall back safely rather than becoming executable styling or navigation.

## Checklist View

Use Checklist for a list of things to finish — a shopping list, a packing list, a set of steps. It is
Card with one addition: you choose which column means *done*, and then each card can be ticked off
from the board. Every card carries a checkbox, and clicking anywhere else on the card ticks it too.

A finished card fills its box, fades, strikes its title, and sinks below the ones still open. The
background stays the same down the whole list, so a finished row reads as finished rather than as a
stripe.

The **Done column** is either a boolean column, or a select column where you say which of its options
count as finished and which one a row returns to when you reopen it. A table of tasks already fits:
its state column arrives with `completed` and `discarded` treated as done.

If a table has neither a boolean nor a select column, add a boolean column to it first.

## Adding a row

Card and Checklist carry an **Add to** line at the bottom whenever the cards can be edited: **Can
edit** is on and Title or Description is set to Column. It creates the row immediately, filled with
each column's starting value, and the new card appears in place ready to edit. There is no form to
fill in first — put the name straight onto the card.

**Note**: a column that cannot be null and has no blank value — a date, an instant, a select with no
options — leaves nothing to start a row from. The line names the column standing in the way instead
of creating a row the table would refuse.

## Sorting what you see

Every Data View has a sort control in its top corner. The sort saved in the view's settings is the
default; choosing another one changes only your own view, and it returns to the default next time the
page loads. A Checklist always sinks finished rows below the rest, whatever else you sort by.

## Ask the assistant to prepare the data

The assistant can create a table, change its columns, build a workflow that normalizes or aggregates
incoming records, write rows, and verify representative results. Where it has been granted the page
tools it can also place the widget and apply the bindings; without them it prepares the data and
reports what to bind.

A useful request is:

> Create a `weekly-metrics` table ready for a Data View, and a workflow that keeps it current.
> Use one row per day and channel, preserve stable IDs, and make the date and value columns the right
> kinds. Then tell me which columns to bind in the Data View.

A good handoff identifies the table slug, suggested View Type, query ordering, and the columns each
part of the presentation binds. You can then apply those bindings in the widget editor.

## When a view needs attention

If a column is not offered where you expect it, confirm the table declares it, then check its kind.
Filtering, ordering, and grouping all need a column that reduces to one comparable value, so a JSON,
object, or block column is offered for none of them, and a list is offered to filters alone.

A write never adds a column. A workflow sending a key the table does not declare is refused, so the
missing column is added to the table first and backfilled second.

If expected rows are missing, inspect the Data View's search, filters, ordering, limit, and offset.
Presentation ordering only works with rows already returned by the query.
