Blocks
Compose the content and the layout of a screen from blocks.
A block is a part of a screen. A view returns blocks, and the client renders each block with its own component. You compose a screen by putting blocks inside other blocks, in the same way that you compose a React tree from components.
This introduction explains the two categories of blocks, how to compose a layout from them, and how to select a block. The page for each block has the full options.
Two categories of blocks
A data block displays the data that your view supplies. table, list, datalist,
and timeline are data blocks. You give a data block your records and the fields
that it must show. The SDK converts each value to its protocol form, and the client
renders it.
table(rows).setFields(orders.pick('reference', 'customer', 'total'))
A container block gives structure to a page. section, panel, tabs, and group
are container blocks. A container block has a content slot that holds other blocks,
and some container blocks have a second slot. A section has an aside slot for
content that goes next to the main content.
section('Orders').setContent([panel([table(rows).setFields(columns)])])
Forms and widgets are blocks too, and they go in the same slots. They have their own introductions: Forms and Widgets.
Compose a layout
Backlit has no grid, no columns, and no spacing options. You declare the structure
of a page, and the client decides the layout from that structure and from the width
that is available. A section with an aside renders as two columns on a wide
screen and as one column on a narrow screen, and your view does not change.
The example below builds a detail page. The section gives the page a heading. Its
content slot has a panel, and its aside slot has a second panel.
import {
callout,
defineResource,
panel,
section,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
section('Order')
.setContent([
panel([
callout('The order is ready to ship.'),
]).setTitle('Activity'),
])
.setAside([
panel([callout('A. Customer')]).setTitle('Customer'),
])
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "section",
"title": "Order",
"slots": {
"content": [
{
"kind": "panel",
"title": "Activity",
"slots": {
"content": [
{
"kind": "callout",
"text": "The order is ready to ship."
}
]
}
}
],
"aside": [
{
"kind": "panel",
"title": "Customer",
"slots": {
"content": [
{
"kind": "callout",
"text": "A. Customer"
}
]
}
}
]
}
}
]
}
}
}The content of a slot is an array of builders, so you compose it with normal TypeScript. Use a condition or an array spread to include a block for some requests only. Create the blocks inside the view callback, so each request gets new builders.
section('Order').setContent([
...(order.isOverdue ? [callout('The payment is overdue.').setTone('warning')] : []),
panel([datalist(order).setFields(orders.pick('reference', 'customer', 'total'))]),
])
Select a block
| Your need | Block |
|---|---|
| Show many records in columns, to scan and compare them | Table |
| Show many records as rows with a title, a description, and metadata | List |
| Show events in time order | Timeline |
| Show one record as labeled values, for a detail page | Datalist |
| Show a short message next to the content that it describes | Callout |
| Divide a page into regions with a heading, filters, and actions | Section |
| Put content inside one surface with a boundary | Panel |
| Switch between sets of content on one page | Tabs |
| Keep related blocks together without a heading or a boundary | Group |
| Show one select filter as a row of buttons above a list | Segments |
Two pairs of blocks are easy to confuse.
Use a section for a region of the page and a panel for one item with a boundary.
A list page is usually a section that has the filters and the actions, with a
panel inside it that has the table.
Use tabs to switch between different content, and segments to switch one list
between the values of one field, such as the status of a subscriber.
Block metadata
Most blocks accept the same optional metadata: a title, a description, a badge, and
a footnote. You set them with methods on the builder, such as setTitle. The client
controls their position and their style, so a title looks the same on each block of
your app.
Blocks and zones
A block gets its data from the view callback, so a change to the data needs a new request for the view. When a part of a page must load again without the other parts, put it in a zone. A zone goes in the same slots as a block, and it has its own callback. See Zones.
When no built-in block fits, an extension can add a block. See Extensions.