Card
A container component that displays content in a compact and organized way.
import { Stack } from 'styled-system/jsx'
import { Button } from '~/components/ui/button'
import { Card } from '~/components/ui/card'
import { Field } from '~/components/ui/field'
export const Demo = (props: Card.RootProps) => {
return (
<Card.Root width="sm" {...props}>
<Card.Header>
<Card.Title>Team Members</Card.Title>
<Card.Description>Add new members to your organisation.</Card.Description>
</Card.Header>
<Card.Body>
<Stack gap="4">
<Field.Root>
<Field.Label>Name</Field.Label>
<Field.Input placeholder="Name" />
</Field.Root>
<Field.Root>
<Field.Label>Email</Field.Label>
<Field.Input type="email" placeholder="Email" />
</Field.Root>
</Stack>
</Card.Body>
<Card.Footer gap="3">
<Button variant="outline">Cancel</Button>
<Button>Invite</Button>
</Card.Footer>
</Card.Root>
)
}
import { Stack } from 'styled-system/jsx'
import { Button } from '~/components/ui/button'
import { Card } from '~/components/ui/card'
import { Field } from '~/components/ui/field'
export const Demo = (props: Card.RootProps) => {
return (
<Card.Root width="sm" {...props}>
<Card.Header>
<Card.Title>Team Members</Card.Title>
<Card.Description>Add new members to your organisation.</Card.Description>
</Card.Header>
<Card.Body>
<Stack gap="4">
<Field.Root>
<Field.Label>Name</Field.Label>
<Field.Input placeholder="Name" />
</Field.Root>
<Field.Root>
<Field.Label>Email</Field.Label>
<Field.Input type="email" placeholder="Email" />
</Field.Root>
</Stack>
</Card.Body>
<Card.Footer gap="3">
<Button variant="outline">Cancel</Button>
<Button>Invite</Button>
</Card.Footer>
</Card.Root>
)
}
Usage
import { Card } from '~/components/ui/card'
Installation
npx @park-ui/cli components add card
1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/card.tsx
'use client'
import type { Assign, PolymorphicProps } from '@ark-ui/react'
import { type HTMLArkProps, ark } from '@ark-ui/react/factory'
import { type CardVariantProps, card } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(card)
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
HTMLDivElement,
Assign<Assign<HTMLStyledProps<'div'>, PolymorphicProps>, CardVariantProps>
>(ark.div, 'root')
export const Body = withContext<HTMLDivElement, Assign<HTMLStyledProps<'div'>, PolymorphicProps>>(
ark.div,
'body',
)
export const Description = withContext<
HTMLDivElement,
Assign<HTMLStyledProps<'div'>, PolymorphicProps>
>(ark.div, 'description')
export const Footer = withContext<HTMLDivElement, Assign<HTMLStyledProps<'div'>, PolymorphicProps>>(
ark.div,
'footer',
)
export const Header = withContext<HTMLDivElement, Assign<HTMLStyledProps<'div'>, PolymorphicProps>>(
ark.div,
'header',
)
export const Title = withContext<
HTMLHeadingElement,
Assign<HTMLStyledProps<'h3'>, HTMLArkProps<'h3'>>
>(ark.h3, 'title')
import { type Assign, type PolymorphicProps, ark } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { card } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(card)
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<Assign<HTMLStyledProps<'div'>, PolymorphicProps<'div'>>>(
ark.div,
'root',
)
export const Body = withContext<Assign<HTMLStyledProps<'div'>, PolymorphicProps<'div'>>>(
ark.div,
'body',
)
export const Description = withContext<Assign<HTMLStyledProps<'div'>, PolymorphicProps<'div'>>>(
ark.div,
'description',
)
export const Footer = withContext<Assign<HTMLStyledProps<'div'>, PolymorphicProps<'div'>>>(
ark.div,
'footer',
)
export const Header = withContext<Assign<HTMLStyledProps<'div'>, PolymorphicProps<'div'>>>(
ark.div,
'header',
)
export const Title = withContext<Assign<HTMLStyledProps<'h3'>, PolymorphicProps<'h3'>>>(
ark.h3,
'title',
)
import { type AccordionVariantProps, card } from 'styled-system/recipes'
import type { Assign, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(card)
export interface RootProps extends Assign<HTMLStyledProps<'div'>, AccordionVariantProps> {}
export const Root = withProvider<RootProps>('div', 'root')
export const Header = withContext<HTMLStyledProps<'div'>>('div', 'header')
export const Body = withContext<HTMLStyledProps<'div'>>('div', 'body')
export const Footer = withContext<HTMLStyledProps<'div'>>('div', 'footer')
export const Title = withContext<HTMLStyledProps<'h3'>>('h3', 'title')
export const Description = withContext<HTMLStyledProps<'div'>>('div', 'description')
2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/card.tsx
.
export * as Card from './styled/card'
export * as Card from './styled/card'
export * as Card from './styled/card'
3
Integrate Recipe
If you're not using @park-ui/preset
, add the following recipe to yourpanda.config.ts
:
import { defineSlotRecipe } from '@pandacss/dev'
export const card = defineSlotRecipe({
className: 'card',
slots: ['root', 'header', 'body', 'footer', 'title', 'description'],
base: {
root: {
bg: 'bg.default',
borderRadius: 'l3',
boxShadow: 'lg',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
position: 'relative',
},
header: {
display: 'flex',
flexDirection: 'column',
gap: '1',
p: '6',
},
body: {
display: 'flex',
flex: '1',
flexDirection: 'column',
pb: '6',
px: '6',
},
footer: {
display: 'flex',
justifyContent: 'flex-end',
pb: '6',
pt: '2',
px: '6',
},
title: {
color: 'fg.default',
textStyle: 'lg',
fontWeight: 'semibold',
},
description: {
color: 'fg.muted',
textStyle: 'sm',
},
},
})