# Card

> Displays a card with header, content, and footer.

**BNA UI** — a React Native / Expo component library.
These components render through `react-native`, not the DOM: there are no HTML
elements, no Tailwind classes and no Radix primitives. Source is copied into your
project and imported through `@/components/ui/*`, `@/components/charts/*`,
`@/hooks/*` and `@/theme/*`. Colours come from the `useColor` hook rather than
hardcoded hex; sizing tokens (`HEIGHT`, `FONT_SIZE`, `BORDER_RADIUS`, `CORNERS`)
come from `@/theme/globals`.

- Docs: https://ui.ahmedbna.com/docs/components/card
- Markdown: https://ui.ahmedbna.com/docs/components/card.md
- Structured JSON (props, usage, source, examples): https://ui.ahmedbna.com/r/ai/card.json
- Install payload (source plus every file it imports): https://ui.ahmedbna.com/r/card.json
- Install: `npx bna-ui add card`
- Registry dependencies: `mode-provider`, `useColorScheme`, `colors`, `useColor`, `globals`, `text`, `view`
- Preview recording: https://demo.ahmedbna.com/0090-card-demo.PNG

---

**Example:** A complete card with header, content, and footer sections

```tsx
// components/demo/card/card-demo.tsx
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Text } from '@/components/ui/text';
import React from 'react';

export function CardDemo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
        <CardDescription>
          This is a description of the card content. It provides additional
          context about what this card contains.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <Text>
          This is the main content area of the card. You can put any content
          here including text, images, forms, or other components.
        </Text>
      </CardContent>
      <CardFooter>
        <Button variant='outline'>Cancel</Button>
        <Button style={{ flex: 1 }}>Confirm</Button>
      </CardFooter>
    </Card>
  );
}
```

## Installation

### CLI

```bash
npx bna-ui add card
```

### Manual

**1.** Copy and paste the following code into your project.

```tsx
// components/ui/card.tsx
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useColor } from '@/hooks/useColor';
import { BORDER_RADIUS } from '@/theme/globals';
import { memo } from 'react';
import {
  TextProps as RNTextProps,
  TextStyle,
  ViewProps as RNViewProps,
  ViewStyle,
} from 'react-native';

interface CardProps extends RNViewProps {
  children: React.ReactNode;
  style?: ViewStyle;
}

export const Card = memo(function Card({
  children,
  style,
  ...props
}: CardProps) {
  const cardColor = useColor('card');
  const foregroundColor = useColor('foreground');

  return (
    <View
      style={[
        {
          width: '100%',
          backgroundColor: cardColor,
          borderRadius: BORDER_RADIUS,
          padding: 18,
          shadowColor: foregroundColor,
          shadowOffset: { width: 0, height: 2 },
          shadowOpacity: 0.05,
          shadowRadius: 3,
          elevation: 2,
        },
        style,
      ]}
      {...props}
    >
      {children}
    </View>
  );
});

interface CardHeaderProps extends RNViewProps {
  children: React.ReactNode;
  style?: ViewStyle;
}

export const CardHeader = memo(function CardHeader({
  children,
  style,
  ...props
}: CardHeaderProps) {
  return (
    <View style={[{ marginBottom: 8 }, style]} {...props}>
      {children}
    </View>
  );
});

interface CardTitleProps extends RNTextProps {
  children: React.ReactNode;
  style?: TextStyle;
}

export const CardTitle = memo(function CardTitle({
  children,
  style,
  ...props
}: CardTitleProps) {
  return (
    <Text
      variant='title'
      style={[
        {
          marginBottom: 4,
        },
        style,
      ]}
      {...props}
    >
      {children}
    </Text>
  );
});

interface CardDescriptionProps extends RNTextProps {
  children: React.ReactNode;
  style?: TextStyle;
}

export const CardDescription = memo(function CardDescription({
  children,
  style,
  ...props
}: CardDescriptionProps) {
  return (
    <Text variant='caption' style={[style]} {...props}>
      {children}
    </Text>
  );
});

interface CardContentProps extends RNViewProps {
  children: React.ReactNode;
  style?: ViewStyle;
}

export const CardContent = memo(function CardContent({
  children,
  style,
  ...props
}: CardContentProps) {
  return (
    <View style={[style]} {...props}>
      {children}
    </View>
  );
});

interface CardFooterProps extends RNViewProps {
  children: React.ReactNode;
  style?: ViewStyle;
}

export const CardFooter = memo(function CardFooter({
  children,
  style,
  ...props
}: CardFooterProps) {
  return (
    <View
      style={[
        {
          marginTop: 16,
          flexDirection: 'row',
          gap: 8,
        },
        style,
      ]}
      {...props}
    >
      {children}
    </View>
  );
});
```

**2.** Update the import paths to match your project setup.

## Usage

```tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
```

```tsx
<Card>
  <CardHeader>
    <CardTitle>Card Title</CardTitle>
    <CardDescription>Card Description</CardDescription>
  </CardHeader>
  <CardContent>
    <p>Card Content</p>
  </CardContent>
  <CardFooter>
    <p>Card Footer</p>
  </CardFooter>
</Card>
```

## Examples

#### Default

**Example:** A complete card with header, content, and footer sections

```tsx
// components/demo/card/card-demo.tsx
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Text } from '@/components/ui/text';
import React from 'react';

export function CardDemo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
        <CardDescription>
          This is a description of the card content. It provides additional
          context about what this card contains.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <Text>
          This is the main content area of the card. You can put any content
          here including text, images, forms, or other components.
        </Text>
      </CardContent>
      <CardFooter>
        <Button variant='outline'>Cancel</Button>
        <Button style={{ flex: 1 }}>Confirm</Button>
      </CardFooter>
    </Card>
  );
}
```

#### Simple

**Example:** A minimal card with just content

```tsx
// components/demo/card/card-simple.tsx
import { Card, CardContent } from '@/components/ui/card';
import { Text } from '@/components/ui/text';
import React from 'react';

export function CardSimple() {
  return (
    <Card>
      <CardContent>
        <Text>
          A simple card with just content. Perfect for displaying basic
          information or messages.
        </Text>
      </CardContent>
    </Card>
  );
}
```

#### With Image

**Example:** Card featuring an image with content below

```tsx
// components/demo/card/card-with-image.tsx
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';
import { Image } from 'react-native';

export function CardWithImage() {
  return (
    <Card>
      <View style={{ borderRadius: 26, overflow: 'hidden', marginBottom: 16 }}>
        <Image
          source={{ uri: 'https://picsum.photos/350/200' }}
          style={{ width: '100%', height: 300 }}
          resizeMode='cover'
        />
      </View>
      <CardHeader>
        <CardTitle>Beautiful Landscape</CardTitle>
        <CardDescription>
          A stunning view captured in the mountains during golden hour.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <Text>
          This image showcases the beauty of nature with its vibrant colors and
          serene atmosphere.
        </Text>
      </CardContent>
      <CardFooter>
        <Button variant='outline'>Share</Button>
        <Button>Download</Button>
      </CardFooter>
    </Card>
  );
}
```

#### With Form

**Example:** Interactive card containing a login form

```tsx
// components/demo/card/card-with-form.tsx
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useColor } from '@/hooks/useColor';
import React, { useState } from 'react';
import { TextInput } from 'react-native';

export function CardWithForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const borderColor = useColor('border');
  const backgroundColor = useColor('background');
  const textColor = useColor('text');

  return (
    <Card>
      <CardHeader>
        <CardTitle>Sign In</CardTitle>
        <CardDescription>
          Enter your credentials to access your account.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <View style={{ gap: 16 }}>
          <View>
            <Text style={{ marginBottom: 8, fontWeight: '500' }}>Email</Text>
            <TextInput
              value={email}
              onChangeText={setEmail}
              placeholder='Enter your email'
              style={{
                borderWidth: 1,
                borderColor,
                borderRadius: 999,
                padding: 12,
                backgroundColor,
                color: textColor,
              }}
              keyboardType='email-address'
              autoCapitalize='none'
            />
          </View>
          <View>
            <Text style={{ marginBottom: 8, fontWeight: '500' }}>Password</Text>
            <TextInput
              value={password}
              onChangeText={setPassword}
              placeholder='Enter your password'
              secureTextEntry
              style={{
                borderWidth: 1,
                borderColor,
                borderRadius: 999,
                padding: 12,
                backgroundColor,
                color: textColor,
              }}
            />
          </View>
        </View>
      </CardContent>
      <CardFooter>
        <Button variant='outline'>Cancel</Button>
        <Button>Sign In</Button>
      </CardFooter>
    </Card>
  );
}
```

#### Statistics

**Example:** Grid of cards displaying key metrics and statistics

```tsx
// components/demo/card/card-stats.tsx
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';

export function CardStats() {
  const stats = [
    { title: 'Total Users', value: '12,543', change: '+12%' },
    { title: 'Revenue', value: '$45,231', change: '+8%' },
    { title: 'Orders', value: '1,234', change: '+23%' },
    { title: 'Growth', value: '15.3%', change: '+4%' },
  ];

  return (
    <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 16 }}>
      {stats.map((stat, index) => (
        <Card key={index} style={{ flex: 1, minWidth: 150 }}>
          <CardHeader>
            <CardTitle style={{ fontSize: 16 }}>{stat.title}</CardTitle>
          </CardHeader>
          <CardContent>
            <Text style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 4 }}>
              {stat.value}
            </Text>
            <Text style={{ color: '#22c55e', fontSize: 14 }}>
              {stat.change} from last month
            </Text>
          </CardContent>
        </Card>
      ))}
    </View>
  );
}
```

#### Notification

**Example:** Card designed for displaying notifications with actions

```tsx
// components/demo/card/card-notification.tsx
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Icon } from '@/components/ui/icon';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { Bell } from 'lucide-react-native';
import React from 'react';

export function CardNotification() {
  return (
    <Card style={{ maxWidth: 400 }}>
      <CardHeader>
        <View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
          <View
            style={{
              width: 40,
              height: 40,
              borderRadius: 20,
              backgroundColor: '#3b82f6',
              alignItems: 'center',
              justifyContent: 'center',
            }}
          >
            <Icon name={Bell} color='white' size={20} />
          </View>
          <View style={{ flex: 1 }}>
            <CardTitle>New Notification</CardTitle>
            <CardDescription>2 minutes ago</CardDescription>
          </View>
        </View>
      </CardHeader>
      <CardContent>
        <Text>
          You have a new message from John Doe. Click to view the full
          conversation and respond.
        </Text>
      </CardContent>
      <CardFooter>
        <Button variant='outline'>Dismiss</Button>
        <Button>View Message</Button>
      </CardFooter>
    </Card>
  );
}
```

#### Pricing

**Example:** Professional pricing cards with feature lists and CTAs

```tsx
// components/demo/card/card-pricing.tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Icon } from '@/components/ui/icon';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { Check } from 'lucide-react-native';
import React from 'react';

export function CardPricing() {
  const plans = [
    {
      name: 'Basic',
      price: '$9',
      description: 'Perfect for individuals',
      features: ['1 Project', '5GB Storage', 'Email Support'],
      popular: false,
    },
    {
      name: 'Pro',
      price: '$29',
      description: 'Best for small teams',
      features: [
        '10 Projects',
        '100GB Storage',
        // 'Priority Support',
        // 'Advanced Analytics',
      ],
      popular: true,
    },
    {
      name: 'Enterprise',
      price: '$99',
      description: 'For large organizations',
      features: [
        'Unlimited Projects',
        '1TB Storage',
        // '24/7 Support',
        // 'Custom Integrations',
      ],
      popular: false,
    },
  ];

  return (
    <View style={{ flexDirection: 'row', gap: 16, flexWrap: 'wrap' }}>
      {plans.map((plan, index) => (
        <Card
          key={index}
          style={{
            flex: 1,
            minWidth: 250,
            borderWidth: plan.popular ? 2 : 1,
            borderColor: plan.popular ? '#3b82f6' : undefined,
          }}
        >
          <CardHeader>
            <View style={{ alignItems: 'center' }}>
              {plan.popular && (
                <View
                  style={{
                    backgroundColor: '#3b82f6',
                    paddingHorizontal: 12,
                    paddingVertical: 4,
                    borderRadius: 12,
                    marginBottom: 8,
                  }}
                >
                  <Text
                    style={{ color: 'white', fontSize: 12, fontWeight: '600' }}
                  >
                    POPULAR
                  </Text>
                </View>
              )}
              <CardTitle>{plan.name}</CardTitle>
              <CardDescription>{plan.description}</CardDescription>
              <Text style={{ fontSize: 32, fontWeight: 'bold', marginTop: 8 }}>
                {plan.price}
                <Text style={{ fontSize: 16, fontWeight: 'normal' }}>
                  /month
                </Text>
              </Text>
            </View>
          </CardHeader>
          <CardContent>
            <View style={{ gap: 8 }}>
              {plan.features.map((feature, featureIndex) => (
                <View
                  key={featureIndex}
                  style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}
                >
                  <Icon name={Check} color='#22c55e' size={16} />
                  <Text>{feature}</Text>
                </View>
              ))}
            </View>
          </CardContent>
          {/* <CardFooter>
            <Button
              variant={plan.popular ? 'default' : 'outline'}
              style={{ width: '100%' }}
            >
              Get Started
            </Button>
          </CardFooter> */}
        </Card>
      ))}
    </View>
  );
}
```

## API Reference

### Card

The main container component that wraps all card content.

| Prop       | Type        | Description                                         |
| ---------- | ----------- | --------------------------------------------------- |
| `children` | `ReactNode` | The card content (typically header/content/footer). |
| `style`    | `ViewStyle` | Additional styles to apply to the card container.   |

### CardHeader

Container for the card's header content, typically containing title and description.

| Prop       | Type        | Description                                               |
| ---------- | ----------- | --------------------------------------------------------- |
| `children` | `ReactNode` | The header content (typically CardTitle/CardDescription). |
| `style`    | `ViewStyle` | Additional styles to apply to the header container.       |

### CardTitle

The main title text of the card.

| Prop       | Type        | Description                                   |
| ---------- | ----------- | --------------------------------------------- |
| `children` | `ReactNode` | The title text content.                       |
| `style`    | `TextStyle` | Additional styles to apply to the title text. |

### CardDescription

Subtitle or description text for the card.

| Prop       | Type        | Description                                         |
| ---------- | ----------- | --------------------------------------------------- |
| `children` | `ReactNode` | The description text content.                       |
| `style`    | `TextStyle` | Additional styles to apply to the description text. |

### CardContent

Container for the main content of the card.

| Prop       | Type        | Description                                          |
| ---------- | ----------- | ---------------------------------------------------- |
| `children` | `ReactNode` | The main content of the card.                        |
| `style`    | `ViewStyle` | Additional styles to apply to the content container. |

### CardFooter

Container for the card's footer content, typically containing actions or additional info.

| Prop       | Type        | Description                                         |
| ---------- | ----------- | --------------------------------------------------- |
| `children` | `ReactNode` | The footer content (typically buttons or actions).  |
| `style`    | `ViewStyle` | Additional styles to apply to the footer container. |

## Design Guidelines

### Visual Hierarchy

Cards help establish clear visual hierarchy in your interface:

- Use **CardTitle** for the primary heading (larger, bolder text)
- Use **CardDescription** for supporting information (smaller, muted text)
- Organize content logically from header to content to footer

### Layout Patterns

Cards work well in various layout patterns:

- **Single cards** for focused content or forms
- **Card grids** for displaying multiple related items
- **Card lists** for sequential content like notifications
- **Dashboard cards** for metrics and statistics

### Content Guidelines

- Keep titles concise and descriptive
- Use descriptions to provide context without overwhelming
- Place primary actions in the footer
- Ensure adequate spacing between sections

### Accessibility

The Card component follows accessibility best practices:

- Semantic structure for screen readers
- Proper text hierarchy with heading roles
- Adequate contrast ratios for all text
- Touch-friendly interactive elements
- Keyboard navigation support

### Responsive Design

Cards automatically adapt to different screen sizes:

- Flexible width that responds to container constraints
- Proper text scaling on different devices
- Consistent spacing across all screen sizes
- Touch-optimized interactive elements
