Skip to content
Backlit
Esc
navigateopen⌘Jpreview
On this page

Datalist

Display one record as a list of labeled values.

A datalist block displays one record through a declared set of fields. Use it for a detail view or for a short record summary.

The fields control the order, labels, and display variants. The data supplies the raw values. The SDK remaps each value to the protocol format before it sends the node.

API

datalist(data: Row): DatalistBuilder<Row>
Method Input Result
setFields Nodeable<Field>[] Sets the fields and their order.
peers ...string[][] Puts each field set on one shared row.
onDefect (defect: Defect) => void Handles values that the SDK cannot put on the wire.

Calling setFields or peers again replaces the previous value.

Basic datalist

Pass one raw record to datalist(data), then set the fields. Only declared fields go into the protocol output.

import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const customers = defineResource('customers', [
  fields.text('name', { label: 'Name' }),
  fields.text('email', {
    label: 'Email',
    format: 'email',
  }),
])

customers.view('detail', () =>
  datalist({
    name: 'A. Customer',
    email: '[email protected]',
  }).setFields(customers.pick('name', 'email'))
)

export default customers
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "customers",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "name",
              "label": "Name"
            },
            {
              "kind": "text",
              "name": "email",
              "label": "Email",
              "format": "email"
            }
          ],
          "data": {
            "name": "A. Customer",
            "email": "[email protected]"
          }
        }
      ]
    }
  }
}

Datalist inside a panel

Put a datalist inside a panel when the record needs a title or a bounded surface. The panel supplies the surrounding metadata. The datalist supplies the labeled values.

import {
  datalist,
  defineResource,
  fields,
  panel,
} from '@backlit/sdk'

const customers = defineResource('customers', [
  fields.text('name', { label: 'Name' }),
  fields.text('email', {
    label: 'Email',
    format: 'email',
  }),
  fields.text('phone', {
    label: 'Phone',
    format: 'phone',
  }),
])

customers.view('detail', () =>
  panel([
    datalist({
      name: 'A. Customer',
      email: '[email protected]',
      phone: '+1 202 555 0147',
    }).setFields(customers.pick('name', 'email', 'phone')),
  ]).setTitle('Customer details', { icon: 'customers' })
)

export default customers
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "customers",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "panel",
          "title": "Customer details",
          "titleIcon": "customers",
          "slots": {
            "content": [
              {
                "kind": "datalist",
                "fields": [
                  {
                    "kind": "text",
                    "name": "name",
                    "label": "Name"
                  },
                  {
                    "kind": "text",
                    "name": "email",
                    "label": "Email",
                    "format": "email"
                  },
                  {
                    "kind": "text",
                    "name": "phone",
                    "label": "Phone",
                    "format": "phone"
                  }
                ],
                "data": {
                  "name": "A. Customer",
                  "email": "[email protected]",
                  "phone": "+1 202 555 0147"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Selected fields

Use resource.pick to select fields and set their display order. Extra keys in the raw record do not go into the protocol output.

import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const customers = defineResource('customers', [
  fields.number('id', { label: 'ID' }),
  fields.text('name', { label: 'Name' }),
  fields.text('email', {
    label: 'Email',
    format: 'email',
  }),
  fields.text('phone', {
    label: 'Phone',
    format: 'phone',
  }),
])

customers.view('detail', () =>
  datalist({
    id: 42,
    name: 'A. Customer',
    email: '[email protected]',
    phone: '+1 202 555 0147',
  })
    .setFields(customers.pick('name', 'phone'))
)

export default customers
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "customers",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "name",
              "label": "Name"
            },
            {
              "kind": "text",
              "name": "phone",
              "label": "Phone",
              "format": "phone"
            }
          ],
          "data": {
            "name": "A. Customer",
            "phone": "+1 202 555 0147"
          }
        }
      ]
    }
  }
}

Peer fields

Use peers when two or more values must share one row. Fields that are not in a peer set stay on separate rows.

import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const orders = defineResource('orders', [
  fields.text('reference', { label: 'Order' }),
  fields.text('status', { label: 'Status' }),
  fields.date('placedAt', {
    label: 'Placed',
    displayVariant: 'date',
  }),
])

orders.view('detail', () =>
  datalist({
    reference: 'ORD-1042',
    status: 'Shipped',
    placedAt: '2026-08-12T09:30:00.000Z',
  })
    .setFields(
      orders.pick('reference', 'status', 'placedAt')
    )
    .peers(['reference', 'status'])
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "reference",
              "label": "Order"
            },
            {
              "kind": "text",
              "name": "status",
              "label": "Status"
            },
            {
              "kind": "date",
              "name": "placedAt",
              "label": "Placed",
              "displayVariant": "date"
            }
          ],
          "peers": [
            [
              "reference",
              "status"
            ]
          ],
          "data": {
            "reference": "ORD-1042",
            "status": "Shipped",
            "placedAt": "2026-08-12T09:30:00.000Z"
          }
        }
      ]
    }
  }
}

Multiple peer rows

Pass multiple field sets to create multiple peer rows.

import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const orders = defineResource('orders', [
  fields.text('reference', { label: 'Order' }),
  fields.text('status', { label: 'Status' }),
  fields.text('carrier', { label: 'Carrier' }),
  fields.text('tracking', { label: 'Tracking number' }),
])

orders.view('detail', () =>
  datalist({
    reference: 'ORD-1042',
    status: 'Shipped',
    carrier: 'Parcel Post',
    tracking: 'PP-1042-2026',
  })
    .setFields(
      orders.pick(
        'reference',
        'status',
        'carrier',
        'tracking'
      )
    )
    .peers(['reference', 'status'], ['carrier', 'tracking'])
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "reference",
              "label": "Order"
            },
            {
              "kind": "text",
              "name": "status",
              "label": "Status"
            },
            {
              "kind": "text",
              "name": "carrier",
              "label": "Carrier"
            },
            {
              "kind": "text",
              "name": "tracking",
              "label": "Tracking number"
            }
          ],
          "peers": [
            [
              "reference",
              "status"
            ],
            [
              "carrier",
              "tracking"
            ]
          ],
          "data": {
            "reference": "ORD-1042",
            "status": "Shipped",
            "carrier": "Parcel Post",
            "tracking": "PP-1042-2026"
          }
        }
      ]
    }
  }
}

Grouped fields

A group combines multiple raw fields into one datalist value. The protocol puts the child values under the group name.

import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const orders = defineResource('orders', [
  fields.text('recipient', { label: 'Recipient' }),
  fields.text('line1', { label: 'Address line 1' }),
  fields.text('city', { label: 'City' }),
  fields.text('postcode', { label: 'Postcode' }),
])

orders.view('detail', () =>
  datalist({
    recipient: 'A. Customer',
    line1: '12 Market Street',
    city: 'London',
    postcode: 'SW1A 1AA',
  }).setFields([
    ...orders.pick('recipient'),
    fields
      .group(
        'address',
        orders.pick('line1', 'city', 'postcode'),
        { label: 'Shipping address' }
      ),
  ])
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "recipient",
              "label": "Recipient"
            },
            {
              "kind": "group",
              "name": "address",
              "label": "Shipping address",
              "fields": [
                {
                  "kind": "text",
                  "name": "line1",
                  "label": "Address line 1"
                },
                {
                  "kind": "text",
                  "name": "city",
                  "label": "City"
                },
                {
                  "kind": "text",
                  "name": "postcode",
                  "label": "Postcode"
                }
              ]
            }
          ],
          "data": {
            "recipient": "A. Customer",
            "address": {
              "line1": "12 Market Street",
              "city": "London",
              "postcode": "SW1A 1AA"
            }
          }
        }
      ]
    }
  }
}

Default remapping

The default remapper converts common adapter values to the protocol format. For example, it converts numeric strings to numbers, 0 or 1 to booleans, and date inputs to ISO strings.

import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const orders = defineResource('orders', [
  fields.number('total', {
    label: 'Total',
    format: 'currency',
    currency: 'USD',
  }),
  fields.boolean('paid', {
    label: 'Paid',
    displayVariant: 'badge',
  }),
  fields.date('placedAt', {
    label: 'Placed',
    displayVariant: 'date',
  }),
])

orders.view('detail', () =>
  datalist({
    total: '149.50',
    paid: 1,
    placedAt: 1_775_987_400_000,
  }).setFields(orders.pick('total', 'paid', 'placedAt'))
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "number",
              "name": "total",
              "format": "currency",
              "currency": "USD",
              "label": "Total"
            },
            {
              "kind": "boolean",
              "name": "paid",
              "label": "Paid",
              "displayVariant": "badge"
            },
            {
              "kind": "date",
              "name": "placedAt",
              "label": "Placed",
              "displayVariant": "date"
            }
          ],
          "data": {
            "total": 149.5,
            "paid": true,
            "placedAt": "2026-04-12T09:50:00.000Z"
          }
        }
      ]
    }
  }
}

Global remapper

Use remappers.registerRemappers when an adapter uses a different value format. The change applies to the role in all blocks. A datalist does not accept local remapper overrides.

import {
  datalist,
  defineResource,
  fields,
  remappers,
} from '@backlit/sdk'

remappers.registerRemappers('display', {
  date: (value) =>
    typeof value === 'number'
      ? new Date(value * 1000).toISOString()
      : null,
})

const orders = defineResource('orders', [
  fields.text('reference', { label: 'Order' }),
  fields.date('placedAt', {
    label: 'Placed',
    displayVariant: 'date',
  }),
])

orders.view('detail', () =>
  datalist({
    reference: 'ORD-1042',
    placedAt: 1_775_987_400,
  }).setFields(orders.pick('reference', 'placedAt'))
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "reference",
              "label": "Order"
            },
            {
              "kind": "date",
              "name": "placedAt",
              "label": "Placed",
              "displayVariant": "date"
            }
          ],
          "data": {
            "reference": "ORD-1042",
            "placedAt": "2026-04-12T09:50:00.000Z"
          }
        }
      ]
    }
  }
}

Defect reporter

A defect occurs when a field is missing or its value cannot be remapped. The SDK leaves that field out of the data and sends the defect to the reporter. If you do not set a reporter, the SDK writes a warning to the console.

import type { Defect } from '@backlit/sdk/types'
import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const defects = new Set<Defect>()
const orders = defineResource('orders', [
  fields.text('reference', { label: 'Order' }),
  fields.number('total', {
    label: 'Total',
    format: 'currency',
    currency: 'USD',
  }),
])

orders.view('detail', () =>
  datalist({
    reference: 'ORD-1042',
    total: 'not available',
  })
    .setFields(orders.pick('reference', 'total'))
    .onDefect((defect) => defects.add(defect))
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "reference",
              "label": "Order"
            },
            {
              "kind": "number",
              "name": "total",
              "format": "currency",
              "currency": "USD",
              "label": "Total"
            }
          ],
          "data": {
            "reference": "ORD-1042"
          }
        }
      ]
    }
  }
}

All options

You can use peer rows and a defect reporter on the same datalist.

import type { Defect } from '@backlit/sdk/types'
import {
  datalist,
  defineResource,
  fields,
} from '@backlit/sdk'

const defects = new Set<Defect>()
const orders = defineResource('orders', [
  fields.text('reference', { label: 'Order' }),
  fields.text('status', { label: 'Status' }),
  fields.number('total', {
    label: 'Total',
    format: 'currency',
    currency: 'USD',
  }),
  fields.date('placedAt', {
    label: 'Placed',
    displayVariant: 'date',
  }),
])

orders.view('detail', () =>
  datalist({
    reference: 'ORD-1042',
    status: 'Shipped',
    total: '149.50',
    placedAt: 1_775_987_400,
  })
    .setFields(
      orders.pick(
        'reference',
        'status',
        'total',
        'placedAt'
      )
    )
    .peers(['reference', 'status'], ['total', 'placedAt'])
    .onDefect((defect) => defects.add(defect))
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "datalist",
          "fields": [
            {
              "kind": "text",
              "name": "reference",
              "label": "Order"
            },
            {
              "kind": "text",
              "name": "status",
              "label": "Status"
            },
            {
              "kind": "number",
              "name": "total",
              "format": "currency",
              "currency": "USD",
              "label": "Total"
            },
            {
              "kind": "date",
              "name": "placedAt",
              "label": "Placed",
              "displayVariant": "date"
            }
          ],
          "peers": [
            [
              "reference",
              "status"
            ],
            [
              "total",
              "placedAt"
            ]
          ],
          "data": {
            "reference": "ORD-1042",
            "status": "Shipped",
            "total": 149.5,
            "placedAt": "1970-01-21T13:19:47.400Z"
          }
        }
      ]
    }
  }
}

Field roles

setRoles({ fieldName: role }) selects roles for individual fields and replaces the previous selections. The default role is display in tables and datalists, and input in form field blocks. See Field roles.

Was this page helpful?