Tsai UI Blocks¶
Reusable section, empty-state, row, and list compositions backed by semantic tokens. The components accept widgets in their visual slots so application typography and business data remain outside the library.
Section Header example Empty State example List Item example List example
Section Header¶
TsaiSectionHeader(
title: 'Transactions',
trailingIcon: const TsaiIcon(LucideIcons.search),
trailingIconSemanticLabel: 'Search transactions',
onTrailingIconPressed: openSearch,
)
Empty State¶
TsaiEmptyState(
icon: const TsaiIcon(LucideIcons.coffee, size: 28),
title: 'No transactions yet',
description: 'New transactions will show up here.',
button: TsaiButton(
label: 'Add money',
size: TsaiButtonSize.medium,
variant: TsaiButtonVariant.secondary,
onPressed: addMoney,
),
)
List Item¶
content is required. icon, trailing, and the standard chevron are
optional. The caller owns typography and layout inside content and
trailing. Set active to display the selected background and provide
onTap when the row is interactive.
TsaiListItem(
icon: const TsaiIcon(LucideIcons.coffee, size: 20),
content: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TsaiTextBody(
'Blue Bottle',
size: TsaiBodySize.medium,
weight: TsaiTextWeight.medium,
),
TsaiTextCaption(
'Coffee ยท Today',
size: TsaiCaptionSize.medium,
weight: TsaiTextWeight.regular,
),
],
),
trailing: const TsaiTextMonoBody(
'-\$4.50',
size: TsaiBodySize.medium,
),
showChevron: true,
onTap: openTransaction,
)
List¶
TsaiList composes a TsaiSectionHeader, ordered TsaiListItem widgets, and
an optional bottom button with the Penpot spacing contract.
TsaiList(
title: 'Transactions',
items: transactionItems,
button: TsaiButton(
label: 'Show all',
size: TsaiButtonSize.medium,
variant: TsaiButtonVariant.outline,
isExpanded: true,
onPressed: showAll,
),
)
List item icons are rendered through the public CircleIcon component, which
keeps the Penpot 40-pixel circle and 20-pixel icon geometry consistent.