Cards

Get a cards view without writing a card, then take over rendering with custom cards or drop to a fully bare card.

Cards without writing a card

A table config renders a cards view too, built from the same columns — stacked label/value pairs that honor the user's column choices and each column's render. That is what the view toggle switches to, and what a viewport under 1024px shows automatically.

defineListConfig<Order>({
	id: 'orders',
	table: { columns },
	// card: undefined  → generated from `columns` (the default)
	// card: item => …  → your own renderer, below
	// card: false      → table only, no toggle, no cards on mobile
})

The auto card is a starting point, not a ceiling: pass a card renderer as soon as a list deserves a designed one.

Custom cards with actions and theme

The card renderer receives the row item plus a ctx object with actions, the active color theme, and the row's index — pass that index along to reuse the very same RowAction[] the table rows use, instead of writing the actions a second time for cards:

defineListConfig<Product>({
	/* … */
	actions: {
		onEdit: item => openEditModal(item),
		onDelete: item => confirmDelete(item),
	},
	card: (item, ctx) => (
		<div className='p-4'>
			<h3 className='font-semibold'>{item.name}</h3>
			<div className='mt-3 flex gap-2'>
				<button
					onClick={() => ctx.actions.onEdit?.(item)}
					className={cn(
						'rounded-md px-3 py-1 text-sm',
						ctx.colorTheme.primaryBg,
						ctx.colorTheme.primaryText
					)}
				>
					Edit
				</button>
			</div>
		</div>
	),
})

Fully custom cards (bareCard)

By default each card is wrapped in listkit's <Card> (border, padding, shadow). Set bareCard: true to render your card output directly — drop in your own card component without double chrome:

defineListConfig<Post>({
	bareCard: true,
	gridCols: 'md:grid-cols-2 lg:grid-cols-3',
	card: post => <MyPostCard {...post} />,
})

When both a card and a table are configured, listkit shows a view toggle and defaults to table on desktop, cards on narrow screens. Set defaultView: 'cards' to open in cards on desktop too (the table stays available via the toggle, and a manual switch still wins):

defineListConfig<Post>({
	defaultView: 'cards',
	card: post => <MyPostCard {...post} />,
	table: { columns },
})

On this page