# Text

> A themed text component with multiple variants for consistent typography across your app.

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

---

**Example:** Basic text component showing different variants

```tsx
// components/demo/text/text-demo.tsx
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';

export function TextDemo() {
  return (
    <View style={{ gap: 16 }}>
      <Text variant='heading'>Heading Text</Text>
      <Text variant='title'>Title Text</Text>
      <Text variant='subtitle'>Subtitle Text</Text>
      <Text variant='body'>
        This is body text that demonstrates the default styling for regular
        content.
      </Text>
      <Text variant='caption'>Caption text for additional information</Text>
      <Text variant='link'>Link text with underline</Text>
    </View>
  );
}
```

## Installation

### CLI

```bash
npx bna-ui add text
```

### Manual

**1.** Install the following dependencies:

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

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

```tsx
// components/ui/text.tsx
import { useColor } from '@/hooks/useColor';
import { FONT_SIZE } from '@/theme/globals';
import React, { forwardRef } from 'react';
import {
  Text as RNText,
  TextProps as RNTextProps,
  TextStyle,
} from 'react-native';

type TextVariant =
  'body' | 'title' | 'subtitle' | 'caption' | 'heading' | 'link';

interface TextProps extends RNTextProps {
  variant?: TextVariant;
  lightColor?: string;
  darkColor?: string;
  children: React.ReactNode;
}

const headingVariants: TextVariant[] = ['heading', 'title', 'subtitle'];

export const Text = React.memo(
  forwardRef<RNText, TextProps>(
    (
      { variant = 'body', lightColor, darkColor, style, children, ...props },
      ref
    ) => {
      const textColor = useColor('text', {
        light: lightColor,
        dark: darkColor,
      });
      const mutedColor = useColor('textMuted');
      const defaultAccessibilityRole = headingVariants.includes(variant)
        ? 'header'
        : undefined;

      const getTextStyle = (): TextStyle => {
        const baseStyle: TextStyle = {
          color: textColor,
        };

        switch (variant) {
          case 'heading':
            return {
              ...baseStyle,
              fontSize: 28,
              fontWeight: '700',
            };
          case 'title':
            return {
              ...baseStyle,
              fontSize: 24,
              fontWeight: '700',
            };
          case 'subtitle':
            return {
              ...baseStyle,
              fontSize: 19,
              fontWeight: '600',
            };
          case 'caption':
            return {
              ...baseStyle,
              fontSize: FONT_SIZE,
              fontWeight: '400',
              color: mutedColor,
            };
          case 'link':
            return {
              ...baseStyle,
              fontSize: FONT_SIZE,
              fontWeight: '500',
              textDecorationLine: 'underline',
            };
          default: // 'body'
            return {
              ...baseStyle,
              fontSize: FONT_SIZE,
              fontWeight: '400',
            };
        }
      };

      return (
        <RNText
          ref={ref}
          style={[getTextStyle(), style]}
          accessibilityRole={defaultAccessibilityRole}
          {...props}
        >
          {children}
        </RNText>
      );
    }
  )
);

Text.displayName = 'Text';
```

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

## Usage

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

```tsx
<Text variant="body">This is body text</Text>
<Text variant="heading">This is a heading</Text>
<Text variant="caption">This is caption text</Text>
```

## Examples

#### Default

**Example:** Basic text component showing different variants

```tsx
// components/demo/text/text-demo.tsx
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';

export function TextDemo() {
  return (
    <View style={{ gap: 16 }}>
      <Text variant='heading'>Heading Text</Text>
      <Text variant='title'>Title Text</Text>
      <Text variant='subtitle'>Subtitle Text</Text>
      <Text variant='body'>
        This is body text that demonstrates the default styling for regular
        content.
      </Text>
      <Text variant='caption'>Caption text for additional information</Text>
      <Text variant='link'>Link text with underline</Text>
    </View>
  );
}
```

#### Typography Scale

**Example:** All text variants showing the typography hierarchy

```tsx
// components/demo/text/text-variants.tsx
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';

export function TextVariants() {
  return (
    <View style={{ gap: 20 }}>
      <View>
        <Text variant='caption' style={{ marginBottom: 4 }}>
          HEADING (28px, weight 700)
        </Text>
        <Text variant='heading'>
          The quick brown fox jumps over the lazy dog
        </Text>
      </View>

      <View>
        <Text variant='caption' style={{ marginBottom: 4 }}>
          TITLE (24px, weight 700)
        </Text>
        <Text variant='title'>The quick brown fox jumps over the lazy dog</Text>
      </View>

      <View>
        <Text variant='caption' style={{ marginBottom: 4 }}>
          SUBTITLE (19px, weight 600)
        </Text>
        <Text variant='subtitle'>
          The quick brown fox jumps over the lazy dog
        </Text>
      </View>

      <View>
        <Text variant='caption' style={{ marginBottom: 4 }}>
          BODY (16px, weight 400)
        </Text>
        <Text variant='body'>
          The quick brown fox jumps over the lazy dog. This is the default text
          variant used for body content and regular paragraphs.
        </Text>
      </View>

      <View>
        <Text variant='caption' style={{ marginBottom: 4 }}>
          CAPTION (16px, weight 400, muted)
        </Text>
        <Text variant='caption'>
          The quick brown fox jumps over the lazy dog
        </Text>
      </View>

      <View>
        <Text variant='caption' style={{ marginBottom: 4 }}>
          LINK (16px, weight 500, underlined)
        </Text>
        <Text variant='link'>The quick brown fox jumps over the lazy dog</Text>
      </View>
    </View>
  );
}
```

#### Custom Colors

**Example:** Text with custom light and dark mode colors

```tsx
// components/demo/text/text-colors.tsx
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';

export function TextColors() {
  return (
    <View style={{ gap: 16 }}>
      <Text variant='subtitle' style={{ marginBottom: 8 }}>
        Custom Color Examples
      </Text>

      <Text variant='body' lightColor='#3b82f6' darkColor='#60a5fa'>
        This text uses custom blue colors for light and dark themes
      </Text>

      <Text variant='body' lightColor='#10b981' darkColor='#34d399'>
        This text uses custom green colors for light and dark themes
      </Text>

      <Text variant='body' lightColor='#f59e0b' darkColor='#fbbf24'>
        This text uses custom amber colors for light and dark themes
      </Text>

      <Text variant='body' lightColor='#ef4444' darkColor='#f87171'>
        This text uses custom red colors for light and dark themes
      </Text>

      <Text variant='body' lightColor='#8b5cf6' darkColor='#a78bfa'>
        This text uses custom purple colors for light and dark themes
      </Text>

      <View style={{ marginTop: 16 }}>
        <Text variant='caption'>
          Note: These colors automatically adapt based on the current theme
          (light/dark mode)
        </Text>
      </View>
    </View>
  );
}
```

## API Reference

### Text

A flexible text component that supports multiple variants and theming.

| Prop         | Type                                                                  | Default  | Description                                      |
| ------------ | --------------------------------------------------------------------- | -------- | ------------------------------------------------ |
| `variant`    | `'body' \| 'title' \| 'subtitle' \| 'caption' \| 'heading' \| 'link'` | `'body'` | The text variant that determines styling.        |
| `lightColor` | `string`                                                              | -        | Custom color for light theme.                    |
| `darkColor`  | `string`                                                              | -        | Custom color for dark theme.                     |
| `children`   | `ReactNode`                                                           | -        | The text content to display.                     |
| `style`      | `TextStyle`                                                           | -        | Additional styles to apply to the text.          |
| `...props`   | `TextProps`                                                           | -        | All other React Native Text props are supported. |

## Variants

### Heading

Large, bold text for main headings (28px, weight 700).

### Title

Medium-large text for section titles (24px, weight 700).

### Subtitle

Medium text for subsections (19px, weight 600).

### Body

Standard text for content (default size, weight 400).

### Caption

Small, muted text for captions and secondary info (default size, weight 400, muted color).

### Link

Text styled as a clickable link (default size, weight 500, underlined).

## Theming

The Text component automatically adapts to your app's theme:

- Uses theme colors for text and muted text
- Supports light and dark mode variants
- Allows custom color overrides via `lightColor` and `darkColor` props
- Integrates with the `useColor` hook

## Accessibility

The Text component is built with accessibility in mind:

- Inherits all React Native Text accessibility features
- Supports dynamic text sizing for users with vision impairments
- Maintains proper contrast ratios with theme colors
- Works with screen readers and other assistive technologies
- Supports semantic roles via standard React Native Text props
