Tabs
Switch between bands of content that a reader takes one at a time.
A tabs block holds named tabs, each with any block or zone. The reader opens one tab at a time. Use it for a record page with more than one band of content: an issue’s overview, its links, and its recipients.
Tabs switch between different content. To switch one list between values of one field, use the segments block instead.
The active tab is local to the renderer. It does not enter the URL, and a tab change fetches nothing: every tab’s content arrives with the view. A zone inside a tab refreshes on its own state, and a zone in a closed tab does not fetch until the tab opens.
API
tabs(items: TabBuilder[]): TabsBuilder
tab(name: string, title: string): TabBuilder
Method on tabs |
Input | Result |
|---|---|---|
setInitial |
string |
Opens the named tab first. |
setWidth |
"full" | "condensed" |
Stretches the tabs across the list, or hugs them. |
setDensity |
"compact" |
Draws smaller tabs. |
Method on tab |
Input | Result |
|---|---|---|
setIcon |
string |
Adds an icon beside the title. |
setCount |
number, { tone?: Tone; variant?: "badge" } |
Adds a count, as muted text or as a badge. |
setContent |
Producer[] |
Sets what the tab holds. Replaces the content. |
Properties that you do not set are not included in the protocol output. A block with no tab, two tabs with one name, or an initial tab the block does not hold fails at resolve.
Basic tabs
Pass the tabs in their display order. The first one opens.
import {
callout,
defineResource,
tab,
tabs,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
tabs([
tab('summary', 'Summary').setContent([
callout('The totals.'),
]),
tab('items', 'Items').setContent([
callout('The lines.'),
]),
])
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "tabs",
"slots": {
"tabs": [
{
"name": "summary",
"title": "Summary",
"slots": {
"content": [
{
"kind": "callout",
"text": "The totals."
}
]
}
},
{
"name": "items",
"title": "Items",
"slots": {
"content": [
{
"kind": "callout",
"text": "The lines."
}
]
}
}
]
}
}
]
}
}
}Initial tab
Name the tab that opens first.
import {
callout,
defineResource,
tab,
tabs,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
tabs([
tab('summary', 'Summary').setContent([
callout('The totals.'),
]),
tab('items', 'Items').setContent([
callout('The lines.'),
]),
]).setInitial('items')
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "tabs",
"initial": "items",
"slots": {
"tabs": [
{
"name": "summary",
"title": "Summary",
"slots": {
"content": [
{
"kind": "callout",
"text": "The totals."
}
]
}
},
{
"name": "items",
"title": "Items",
"slots": {
"content": [
{
"kind": "callout",
"text": "The lines."
}
]
}
}
]
}
}
]
}
}
}Icon and count
A tab can carry an icon and a count. The renderer formats the count in the
client’s locale. Without a variant the count draws as muted text; badge draws
it as a pill in its tone.
import {
callout,
defineResource,
tab,
tabs,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
tabs([
tab('summary', 'Summary')
.setIcon('receipt')
.setContent([callout('The totals.')]),
tab('items', 'Items')
.setCount(4)
.setContent([callout('The lines.')]),
tab('returns', 'Returns')
.setCount(1, { tone: 'danger', variant: 'badge' })
.setContent([
callout('One line came back.').setTone('danger'),
]),
])
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "tabs",
"slots": {
"tabs": [
{
"name": "summary",
"title": "Summary",
"icon": "receipt",
"slots": {
"content": [
{
"kind": "callout",
"text": "The totals."
}
]
}
},
{
"name": "items",
"title": "Items",
"count": 4,
"slots": {
"content": [
{
"kind": "callout",
"text": "The lines."
}
]
}
},
{
"name": "returns",
"title": "Returns",
"count": 1,
"countTone": "danger",
"countVariant": "badge",
"slots": {
"content": [
{
"kind": "callout",
"text": "One line came back.",
"tone": "danger"
}
]
}
}
]
}
}
]
}
}
}Width
full stretches the tabs across the list. condensed hugs their content, which
is the default.
import {
callout,
defineResource,
tab,
tabs,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
tabs([
tab('summary', 'Summary').setContent([
callout('The totals.'),
]),
tab('items', 'Items').setContent([
callout('The lines.'),
]),
]).setWidth('full')
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "tabs",
"width": "full",
"slots": {
"tabs": [
{
"name": "summary",
"title": "Summary",
"slots": {
"content": [
{
"kind": "callout",
"text": "The totals."
}
]
}
},
{
"name": "items",
"title": "Items",
"slots": {
"content": [
{
"kind": "callout",
"text": "The lines."
}
]
}
}
]
}
}
]
}
}
}Density
compact draws smaller tabs, for a header that must not dominate the content.
import {
callout,
defineResource,
tab,
tabs,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
tabs([
tab('summary', 'Summary').setContent([
callout('The totals.'),
]),
tab('items', 'Items').setContent([
callout('The lines.'),
]),
]).setDensity('compact')
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "tabs",
"density": "compact",
"slots": {
"tabs": [
{
"name": "summary",
"title": "Summary",
"slots": {
"content": [
{
"kind": "callout",
"text": "The totals."
}
]
}
},
{
"name": "items",
"title": "Items",
"slots": {
"content": [
{
"kind": "callout",
"text": "The lines."
}
]
}
}
]
}
}
]
}
}
}