import { DataCard } from '@coinbase/cds-web/alpha/data-card'
DataCard is a flexible card component for displaying data with visualizations. It wraps CardRoot and provides a structured layout for thumbnails, titles, subtitles, and visualization content like progress bars or circles.
Migration from Legacy DataCard
The new DataCard from @coinbase/cds-web/alpha/data-card replaces the legacy DataCard. The new version provides more flexibility with custom layouts and visualization components.
Before:
import { DataCard } from '@coinbase/cds-web/cards/DataCard';
<DataCard
title="Progress"
description="45% complete"
progress={0.45}
progressVariant="bar"
startLabel="0"
endLabel="45"
/>;
After:
import { DataCard } from '@coinbase/cds-web/alpha/data-card';
<DataCard
title="Progress"
subtitle="45% complete"
layout="vertical"
thumbnail={<RemoteImage src={assetUrl} shape="circle" size="l" />}
>
<ProgressBarWithFixedLabels startLabel={0} endLabel={45} labelPlacement="below">
<ProgressBar accessibilityLabel="45% complete" progress={0.45} weight="semiheavy" />
</ProgressBarWithFixedLabels>
</DataCard>;
Basic Examples
DataCard supports two layouts: vertical (stacked) and horizontal (side-by-side). Pass visualization components as children.
function Example() { const exampleThumbnail = ( <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" subtitle="Progress indicator" thumbnail={exampleThumbnail} title="Progress Bar Card" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 25.25% </Text> } > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={45} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="45% complete" progress={0.45} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> <DataCard layout="horizontal" subtitle="Circular progress" thumbnail={exampleThumbnail} title="Progress Circle Card" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 25.25% </Text> } > <Box alignItems="center" height="100%"> <ProgressCircle accessibilityLabel="60% complete" progress={0.6} size={100} weight="heavy" /> </Box> </DataCard> </VStack> ); }
Layout Variations
Use layout="vertical" for stacked layouts (thumbnail on left, visualization below) or layout="horizontal" for side-by-side layouts (header on left, visualization on right).
function Example() { const exampleThumbnail = ( <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" subtitle="Vertical layout stacks content" thumbnail={exampleThumbnail} title="Vertical Layout" > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={75} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="75% complete" progress={0.75} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> <DataCard layout="horizontal" subtitle="Horizontal layout places content side by side" thumbnail={exampleThumbnail} title="Horizontal Layout" > <Box alignItems="center" height="100%"> <ProgressCircle accessibilityLabel="75% complete" progress={0.75} size={100} weight="heavy" /> </Box> </DataCard> </VStack> ); }
Title Accessory
Use titleAccessory to display supplementary information inline with the title, such as trends, percentages, or status indicators.
function Example() { const exampleThumbnail = ( <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" subtitle="With positive trend" thumbnail={exampleThumbnail} title="Positive Trend" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 8.5% </Text> } > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={90} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="90% complete" color="fgPositive" progress={0.9} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> <DataCard layout="horizontal" subtitle="Time remaining" thumbnail={exampleThumbnail} title="Countdown" titleAccessory={ <Text color="fgMuted" font="label1"> 2h left </Text> } > <Box alignItems="center" height="100%"> <ProgressCircle accessibilityLabel="70% complete" progress={0.7} size={100} weight="heavy" /> </Box> </DataCard> </VStack> ); }
Interactive Cards
Use renderAsPressable to make the card interactive. You can render as a button with onClick or as a link with as="a" and href.
function Example() { const ref1 = useRef(null); const ref2 = useRef(null); const exampleThumbnail = ( <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard ref={ref1} renderAsPressable layout="vertical" onClick={() => alert('Progress bar card clicked!')} subtitle="Clickable progress card" thumbnail={exampleThumbnail} title="Click to View Details" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 8.5% </Text> } > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={75} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="75% complete" progress={0.75} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> <DataCard ref={ref2} renderAsPressable as="a" href="https://www.coinbase.com" layout="horizontal" subtitle="Card with link" target="_blank" thumbnail={exampleThumbnail} title="Open in New Tab" titleAccessory={ <Text color="fgMuted" font="label1"> External </Text> } > <Box alignItems="center" height="100%"> <ProgressCircle accessibilityLabel="85% complete" progress={0.85} size={100} weight="heavy" /> </Box> </DataCard> </VStack> ); }
Style Customization
Use styles and classNames props to customize specific parts of the card layout.
function Example() { const exampleThumbnail = ( <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" styles={{ root: { borderWidth: 2, borderColor: '#0066FF' }, }} subtitle="Custom border" thumbnail={exampleThumbnail} title="Custom Root Styles" > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={50} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="50% complete" progress={0.5} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> <DataCard layout="horizontal" styles={{ root: { backgroundColor: '#F5F5F5' }, headerContainer: { paddingInlineStart: 'var(--space-4)' }, }} subtitle="Custom background and padding" thumbnail={exampleThumbnail} title="Custom Layout Styles" > <Box alignItems="center" height="100%"> <ProgressCircle accessibilityLabel="70% complete" progress={0.7} size={100} weight="heavy" /> </Box> </DataCard> </VStack> ); }
Multiple Cards
DataCards work well in lists or dashboards to display multiple data points.
function Example() { const exampleThumbnail = ( <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" subtitle="Daily goal progress" thumbnail={exampleThumbnail} title="Steps Today" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> 6,500 / 10,000 </Text> } > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={65} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="65% complete" progress={0.65} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> <DataCard layout="horizontal" subtitle="Weekly completion" thumbnail={exampleThumbnail} title="Workout Goal" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> 5 / 7 days </Text> } > <Box alignItems="center" height="100%"> <ProgressCircle accessibilityLabel="71% complete" color="fgPositive" progress={0.71} size={100} weight="heavy" /> </Box> </DataCard> </VStack> ); }
With LineChart
DataCard can also display chart visualizations like LineChart for showing price trends or time-series data.
function Example() { const lineChartData = useMemo( () => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58, 42, 65, 78, 55, 40, 62], [], ); const lineChartSeries = useMemo( () => [ { id: 'price', data: lineChartData, color: 'var(--color-accentBoldBlue)', }, ], [lineChartData], ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" subtitle="Price trend" thumbnail={ <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> } title="Line Chart Card" > <LineChart showArea accessibilityLabel="Ethereum price chart" areaType="dotted" height={120} inset={0} series={lineChartSeries} /> </DataCard> <DataCard layout="vertical" subtitle="Price trend" thumbnail={ <RemoteImage alt="Bitcoin" aria-hidden="true" shape="circle" size="l" src={assets.btc.imageUrl} /> } title="Chart with Trend" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 25.25% </Text> } > <LineChart showArea accessibilityLabel="Bitcoin price chart" areaType="dotted" height={100} inset={0} series={lineChartSeries} /> </DataCard> <DataCard renderAsPressable as="a" href="https://www.coinbase.com" layout="vertical" subtitle="Clickable line chart card" target="_blank" thumbnail={ <RemoteImage alt="Ethereum" aria-hidden="true" shape="circle" size="l" src={ethBackground} /> } title="Actionable Chart Card" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 8.5% </Text> } > <LineChart showArea accessibilityLabel="Ethereum price chart" areaType="dotted" height={120} inset={0} series={lineChartSeries} /> </DataCard> </VStack> ); }
Accessibility
Ensure all visualization components have appropriate accessibilityLabel props to convey the progress information to screen readers.
function Example() { const exampleThumbnail = ( <RemoteImage alt="Ethereum logo" shape="circle" size="l" src={ethBackground} /> ); return ( <VStack gap={2} width={480}> <DataCard layout="vertical" subtitle="Portfolio allocation" thumbnail={exampleThumbnail} title="ETH Holdings" titleAccessory={ <Text dangerouslySetColor="rgb(var(--green70))" font="label1"> ↗ 12.5% </Text> } > <Box paddingTop={5}> <ProgressBarWithFixedLabels endLabel={80} labelPlacement="below" startLabel={0}> <ProgressBar accessibilityLabel="ETH holdings at 80% of target, currently $4,000 of $5,000 goal" progress={0.8} weight="semiheavy" /> </ProgressBarWithFixedLabels> </Box> </DataCard> </VStack> ); }