# Icon

> A themed icon component with support for Lucide React Native icons.

**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/icon
- Markdown: https://ui.ahmedbna.com/docs/components/icon.md
- Structured JSON (props, usage, source, examples): https://ui.ahmedbna.com/r/ai/icon.json
- Install payload (source plus every file it imports): https://ui.ahmedbna.com/r/icon.json
- Install: `npx bna-ui add icon`
- npm dependencies: `lucide-react-native`, `react-native-svg`
- Registry dependencies: `mode-provider`, `useColorScheme`, `colors`, `useColor`, `globals`, `text`, `view`
- Preview recording: https://demo.ahmedbna.com/0152-icon-demo.PNG

---

**Example:** A basic icon with default styling

```tsx
// components/demo/icon/icon-demo.tsx
import { Icon } from '@/components/ui/icon';
import { Heart } from 'lucide-react-native';
import React from 'react';

export function IconDemo() {
  return <Icon name={Heart} size={24} />;
}
```

## Installation

### CLI

```bash
npx bna-ui add icon
```

### Manual

**1.** Install the following dependencies:

```bash
npx expo install lucide-react-native
```

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

```tsx
// components/ui/icon.tsx
import { useColor } from '@/hooks/useColor';
import { LucideProps } from 'lucide-react-native';
import React from 'react';

export type Props = LucideProps & {
  lightColor?: string;
  darkColor?: string;
  name: React.ComponentType<LucideProps>;
};

export function Icon({
  lightColor,
  darkColor,
  name: IconComponent,
  color,
  size = 24,
  strokeWidth = 1.8,
  accessible = false,
  ...rest
}: Props) {
  const themedColor = useColor('icon', { light: lightColor, dark: darkColor });

  // Use provided color prop if available, otherwise use themed color
  const iconColor = color || themedColor;

  return (
    <IconComponent
      color={iconColor}
      size={size}
      strokeWidth={strokeWidth}
      strokeLinecap='round'
      accessible={accessible}
      {...rest}
    />
  );
}
```

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

## Usage

```tsx
import { Icon } from '@/components/ui/icon';
import { Heart, Star, Home } from 'lucide-react-native';
```

```tsx
<Icon name={Heart} size={24} />
<Icon name={Star} color="#FFD700" />
<Icon name={Home} lightColor="#000" darkColor="#fff" />
```

## Examples

#### Default

**Example:** A basic icon with default styling

```tsx
// components/demo/icon/icon-demo.tsx
import { Icon } from '@/components/ui/icon';
import { Heart } from 'lucide-react-native';
import React from 'react';

export function IconDemo() {
  return <Icon name={Heart} size={24} />;
}
```

#### Sizes

**Example:** Icons in different sizes

```tsx
// components/demo/icon/icon-sizes.tsx
import { Icon } from '@/components/ui/icon';
import { View } from '@/components/ui/view';
import { Star } from 'lucide-react-native';
import React from 'react';

export function IconSizes() {
  const sizes = [16, 20, 24, 32, 40, 48];

  return (
    <View
      style={{
        flexDirection: 'row',
        alignItems: 'center',
        gap: 16,
        flexWrap: 'wrap',
      }}
    >
      {sizes.map((size) => (
        <Icon key={size} name={Star} size={size} color='#FFD700' />
      ))}
    </View>
  );
}
```

#### Colors

**Example:** Icons with custom colors and themed colors

```tsx
// components/demo/icon/icon-colors.tsx
import { Icon } from '@/components/ui/icon';
import { View } from '@/components/ui/view';
import { Circle } from 'lucide-react-native';
import React from 'react';

export function IconColors() {
  const colors = [
    '#FF6B6B', // Red
    '#4ECDC4', // Teal
    '#45B7D1', // Blue
    '#96CEB4', // Green
    '#FECA57', // Yellow
    '#FF9FF3', // Pink
    '#54A0FF', // Light Blue
    '#5F27CD', // Purple
  ];

  return (
    <View
      style={{
        flexDirection: 'row',
        alignItems: 'center',
        gap: 12,
        flexWrap: 'wrap',
      }}
    >
      {colors.map((color, index) => (
        <Icon
          key={index}
          name={Circle}
          size={24}
          color={color}
          fill={color}
          fillOpacity={0.2}
        />
      ))}
    </View>
  );
}
```

#### Stroke Weights

**Example:** Icons with different stroke weights

```tsx
// components/demo/icon/icon-stroke.tsx
import { Icon } from '@/components/ui/icon';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { Zap } from 'lucide-react-native';
import React from 'react';

export function IconStroke() {
  const strokeWeights = [
    { weight: 1, label: 'Light' },
    { weight: 1.5, label: 'Regular' },
    { weight: 2, label: 'Medium' },
    { weight: 2.5, label: 'Bold' },
  ];

  return (
    <View style={{ gap: 16 }}>
      {strokeWeights.map(({ weight, label }) => (
        <View
          key={weight}
          style={{
            flexDirection: 'row',
            alignItems: 'center',
            gap: 12,
          }}
        >
          <Icon name={Zap} size={24} strokeWidth={weight} color='#F39C12' />
          <Text variant='body' style={{ minWidth: 60 }}>
            {label}
          </Text>
        </View>
      ))}
    </View>
  );
}
```

#### Interactive Icons

**Example:** Icons with press and hover interactions

```tsx
// components/demo/icon/icon-interactive.tsx
import { Button } from '@/components/ui/button';
import { Icon } from '@/components/ui/icon';
import { View } from '@/components/ui/view';
import { Bookmark, Heart, Share, ThumbsUp } from 'lucide-react-native';
import React, { useState } from 'react';

export function IconInteractive() {
  const [liked, setLiked] = useState(false);
  const [thumbsUp, setThumbsUp] = useState(false);
  const [bookmarked, setBookmarked] = useState(false);

  const iconButtons = [
    {
      icon: Heart,
      active: liked,
      onPress: () => setLiked(!liked),
      activeColor: '#FF6B6B',
      inactiveColor: '#888',
    },
    {
      icon: ThumbsUp,
      active: thumbsUp,
      onPress: () => setThumbsUp(!thumbsUp),
      activeColor: '#4ECDC4',
      inactiveColor: '#888',
    },
    {
      icon: Bookmark,
      active: bookmarked,
      onPress: () => setBookmarked(!bookmarked),
      activeColor: '#FECA57',
      inactiveColor: '#888',
    },
    {
      icon: Share,
      active: false,
      onPress: () => {},
      activeColor: '#45B7D1',
      inactiveColor: '#888',
    },
  ];

  return (
    <View
      style={{
        flexDirection: 'row',
        gap: 20,
        alignItems: 'center',
      }}
    >
      {iconButtons.map(
        ({ icon, active, onPress, activeColor, inactiveColor }, index) => (
          <Button key={index} variant='ghost' size='icon' onPress={onPress}>
            <Icon
              name={icon}
              size={24}
              color={active ? activeColor : inactiveColor}
              fill={active ? activeColor : 'transparent'}
              fillOpacity={active ? 0.2 : 0}
            />
          </Button>
        )
      )}
    </View>
  );
}
```

#### Icon Grid

**Example:** A grid of commonly used icons

```tsx
// components/demo/icon/icon-grid.tsx
import { Icon } from '@/components/ui/icon';
import { View } from '@/components/ui/view';
import {
  Bell,
  Calendar,
  Camera,
  Download,
  Edit,
  Heart,
  Home,
  Mail,
  Minus,
  Plus,
  Search,
  Settings,
  Star,
  Trash,
  Upload,
  User,
} from 'lucide-react-native';
import React from 'react';

export function IconGrid() {
  const icons = [
    Home,
    Search,
    Bell,
    User,
    Settings,
    Heart,
    Star,
    Mail,
    Calendar,
    Camera,
    Download,
    Upload,
    Edit,
    Trash,
    Plus,
    Minus,
  ];

  return (
    <View
      style={{
        flexDirection: 'row',
        flexWrap: 'wrap',
        gap: 16,
      }}
    >
      {icons.map((IconComponent, index) => (
        <View
          key={index}
          style={{
            padding: 12,
            backgroundColor: '#f8f9fa',
            borderRadius: 8,
            alignItems: 'center',
            justifyContent: 'center',
            width: 48,
            height: 48,
          }}
        >
          <Icon name={IconComponent} size={20} color='#495057' />
        </View>
      ))}
    </View>
  );
}
```

#### Themed Icons

**Example:** Icons that adapt to light and dark themes

```tsx
// components/demo/icon/icon-themed.tsx
import { Icon } from '@/components/ui/icon';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { Monitor, Moon, Palette, Sun } from 'lucide-react-native';
import React from 'react';

export function IconThemed() {
  const themedIcons = [
    {
      icon: Sun,
      label: 'Light Theme',
      lightColor: '#FFA500',
      darkColor: '#FFD700',
    },
    {
      icon: Moon,
      label: 'Dark Theme',
      lightColor: '#4A5568',
      darkColor: '#E2E8F0',
    },
    {
      icon: Monitor,
      label: 'System',
      lightColor: '#2D3748',
      darkColor: '#F7FAFC',
    },
    {
      icon: Palette,
      label: 'Custom',
      lightColor: '#E53E3E',
      darkColor: '#FC8181',
    },
  ];

  return (
    <View style={{ gap: 16 }}>
      {themedIcons.map(({ icon, label, lightColor, darkColor }, index) => (
        <View
          key={index}
          style={{
            flexDirection: 'row',
            alignItems: 'center',
            gap: 12,
          }}
        >
          <Icon
            name={icon}
            size={24}
            lightColor={lightColor}
            darkColor={darkColor}
          />
          <Text variant='body'>{label}</Text>
        </View>
      ))}
    </View>
  );
}
```

## API Reference

### Icon

The main icon component that renders Lucide React Native icons with theming support.

| Prop          | Type                               | Default | Description                                           |
| ------------- | ---------------------------------- | ------- | ----------------------------------------------------- |
| `name`        | `React.ComponentType<LucideProps>` | -       | The Lucide icon component to render.                  |
| `size`        | `number`                           | `24`    | The size of the icon in pixels.                       |
| `color`       | `string`                           | -       | Custom color for the icon.                            |
| `lightColor`  | `string`                           | -       | Color to use in light theme.                          |
| `darkColor`   | `string`                           | -       | Color to use in dark theme.                           |
| `strokeWidth` | `number`                           | `1.8`   | The stroke width of the icon.                         |
| `...rest`     | `LucideProps`                      | -       | Additional props passed to the Lucide icon component. |

### LucideProps

The Icon component accepts all props from Lucide React Native icons:

| Prop             | Type     | Default | Description                      |
| ---------------- | -------- | ------- | -------------------------------- |
| `strokeLinecap`  | `string` | `round` | The line cap style for strokes.  |
| `strokeLinejoin` | `string` | -       | The line join style for strokes. |
| `fill`           | `string` | -       | Fill color for the icon.         |
| `fillOpacity`    | `number` | -       | Opacity of the fill color.       |
| `strokeOpacity`  | `number` | -       | Opacity of the stroke color.     |

## Accessibility

The Icon component is built with accessibility in mind:

- Icons are decorative by default and hidden from screen readers
- When icons convey important information, wrap them with accessible text
- Proper color contrast for themed icons
- Supports dynamic text sizing through size prop

## Common Icon Patterns

### With Labels

```tsx
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';

<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
  <Icon name={Heart} size={16} />
  <Text>Favorites</Text>
</View>;
```

### As Buttons

```tsx
import { Pressable } from 'react-native';

<Pressable onPress={handlePress}>
  <Icon name={Settings} size={24} />
</Pressable>;
```

### Navigation Icons

```tsx
<View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
  <Icon name={Home} />
  <Icon name={Search} />
  <Icon name={Bell} />
  <Icon name={User} />
</View>
```
