Panel
Group related content inside one bounded surface.
A panel block makes a set of content read as one item. Use it for an order summary, a group of settings, or another part of a page that needs a visual boundary.
The panel holds content in the order that you provide it. Its title, description, badge, and footnote are optional. The renderer controls their position and visual style.
API
panel(content: Producer[]): PanelBuilder
| Method | Input | Result |
|---|---|---|
setTitle |
string, { icon?: string } |
Adds a title and an optional icon. |
setDescription |
string, { icon?: string } |
Adds supporting text and an optional icon. |
setBadge |
string, { tone?: Tone, icon?: string } |
Adds a short status label. |
setFootnote |
string, { icon?: string } |
Adds text after the panel content. |
setFilters |
StateBinding<FilterBar> |
Places a filter bar in the panel header. |
Properties that you do not set are not included in the protocol output.
Basic panel
Pass the panel content as an array. The panel can hold any block or zone.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')])
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Title
Add a title when the panel content needs a name.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setTitle(
'Order 1042'
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"title": "Order 1042",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Title icon
Pass an icon token with the title. The renderer resolves the token through its icon registry.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setTitle(
'Order 1042',
{
icon: 'orders',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"title": "Order 1042",
"titleIcon": "orders",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Description
Add a description for supporting information about the complete panel.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([
callout('This order is ready to ship.'),
]).setDescription(
'Placed by A. Customer on 12 August 2026.'
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"description": "Placed by A. Customer on 12 August 2026.",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Description icon
Pass an icon token when the description needs a visual marker.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([
callout('This order is ready to ship.'),
]).setDescription(
'Placed by A. Customer on 12 August 2026.',
{ icon: 'activity' }
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"description": "Placed by A. Customer on 12 August 2026.",
"descriptionIcon": "activity",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Badge
Add a badge for a short qualifier or status. If you do not set a tone, the renderer uses its default badge style.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'Priority'
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "Priority",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Badge tones
A badge tone gives semantic meaning to its status. The renderer controls the color for each tone.
Neutral
Use neutral for a status that does not need emphasis.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'Standard',
{
tone: 'neutral',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "Standard",
"badgeTone": "neutral",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Info
Use info for a current state that does not report success, risk, or failure.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'In transit',
{
tone: 'info',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "In transit",
"badgeTone": "info",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Success
Use success for a completed or intended state.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'Paid',
{
tone: 'success',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "Paid",
"badgeTone": "success",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Warning
Use warning for a state that needs attention.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'Delayed',
{
tone: 'warning',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "Delayed",
"badgeTone": "warning",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Danger
Use danger for a failed or destructive state.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'Payment failed',
{
tone: 'danger',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "Payment failed",
"badgeTone": "danger",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Badge icon
A badge can include an icon token and a tone.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([callout('This order is ready to ship.')]).setBadge(
'Shipped',
{
icon: 'shipping',
tone: 'success',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"badge": "Shipped",
"badgeTone": "success",
"badgeIcon": "shipping",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Footnote
Add a footnote for information that applies after the complete panel content.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([
callout('This order is ready to ship.'),
]).setFootnote('Carrier updates can take up to one hour.')
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"footnote": "Carrier updates can take up to one hour.",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Footnote icon
Pass an icon token when the footnote needs a visual marker.
import {
callout,
defineResource,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
orders.view('detail', () =>
panel([
callout('This order is ready to ship.'),
]).setFootnote(
'Carrier updates can take up to one hour.',
{ icon: 'activity' }
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"footnote": "Carrier updates can take up to one hour.",
"footnoteIcon": "activity",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order is ready to ship."
}
]
}
}
]
}
}
}Filters
Pass the filter binding from the current view or zone. The protocol output includes the current resource and view address with the filter declarations.
import {
callout,
defineFilters,
defineResource,
filters,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
const orderFilters = defineFilters([
filters.text('search').setLabel('Search orders'),
])
orders.view(
'detail',
{ filters: orderFilters },
(_ctx, view) =>
panel([
callout('Three orders match the current search.'),
]).setFilters(view.state.filters)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"slots": {
"content": [
{
"kind": "callout",
"text": "Three orders match the current search."
}
],
"filters": {
"kind": "filters",
"resource": "orders",
"view": "detail",
"keyword": "f",
"definesResult": true,
"dependsOnResult": false,
"filters": [
{
"kind": "text",
"name": "search",
"label": "Search orders"
}
]
}
}
}
]
}
}
}All options
You can set all panel metadata, filters, and content on the same panel.
import {
callout,
defineFilters,
defineResource,
filters,
panel,
} from '@backlit/sdk'
const orders = defineResource('orders', [])
const orderFilters = defineFilters([
filters.text('search').setLabel('Search activity'),
])
orders.view(
'detail',
{ filters: orderFilters },
(_ctx, view) =>
panel([
callout(
'This order left the warehouse at 09:30.'
).setTone('success'),
])
.setTitle('Order 1042', { icon: 'orders' })
.setDescription(
'Placed by A. Customer on 12 August 2026.',
{
icon: 'activity',
}
)
.setBadge('Shipped', {
icon: 'shipping',
tone: 'success',
})
.setFilters(view.state.filters)
.setFootnote(
'Carrier updates can take up to one hour.',
{
icon: 'activity',
}
)
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "detail",
"slots": {
"content": [
{
"kind": "panel",
"title": "Order 1042",
"titleIcon": "orders",
"description": "Placed by A. Customer on 12 August 2026.",
"descriptionIcon": "activity",
"badge": "Shipped",
"badgeTone": "success",
"badgeIcon": "shipping",
"footnote": "Carrier updates can take up to one hour.",
"footnoteIcon": "activity",
"slots": {
"content": [
{
"kind": "callout",
"text": "This order left the warehouse at 09:30.",
"tone": "success"
}
],
"filters": {
"kind": "filters",
"resource": "orders",
"view": "detail",
"keyword": "f",
"definesResult": true,
"dependsOnResult": false,
"filters": [
{
"kind": "text",
"name": "search",
"label": "Search activity"
}
]
}
}
}
]
}
}
}Actions and conditions
setActions([visitTo(...), submitTo(...)]) replaces the header controls.
Each control requires text or an icon. These blocks have no row, so supply
fixed argument values. See Targets.
revealWhen(condition) controls the block inside a form. It has no enable
condition. See Form conditions.