> ## Documentation Index
> Fetch the complete documentation index at: https://docs.launchtoday.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Component Development

> Guide to creating and using reusable components in the mobile app

## Component Architecture

The Launch mobile app uses a well-organized component system that promotes reusability, consistency, and maintainability.

## Prerequisites

* Familiarity with `apps/mobile/components`
* `AppText` and base components available

## Steps

## Common Components

Components live in a flat `components/` folder. Here are a few real examples
from the codebase:

<CodeGroup>
  ```typescript AuthButton theme={null}
  import { AuthButton } from "@/components/auth-button";

  <AuthButton
    provider="apple"
    text="Continue with Apple"
    onPress={handleAppleSignIn}
  />
  ```

  ```typescript AppText theme={null}
  import { AppText } from "@/components/app-text";

  <AppText className="text-lg font-bold text-center">Hello World</AppText>
  ```

  ```typescript ScreenContainer theme={null}
  import { ScreenContainer } from "@/components/screen-container";

  export default function MyScreen() {
    return (
      <ScreenContainer>
        {/* Your screen content */}
      </ScreenContainer>
    );
  }
  ```

  ```typescript ModelSelect theme={null}
  import { ModelSelect } from "@/components/model-select";

  <ModelSelect value={model} onValueChange={setModel} />
  ```
</CodeGroup>

## Creating New Components

### Component Template

```typescript theme={null}
// components/ui/my-component.tsx
import { View } from "react-native";
import { AppText } from "./app-text";
import { getCopy } from "@/config/launch.config";

interface MyComponentProps {
  title: string;
  variant?: "primary" | "secondary";
  onPress?: () => void;
  className?: string;
}

export function MyComponent({
  title,
  variant = "primary",
  onPress,
  className = "",
}: MyComponentProps) {
  const variantStyles = {
    primary: "bg-blue-500 text-white",
    secondary: "bg-gray-200 text-gray-800",
  };

  return (
    <View className={`p-4 rounded-lg ${variantStyles[variant]} ${className}`}>
      <AppText className="font-bold">{title}</AppText>
    </View>
  );
}
```

## Troubleshooting

* **Styles not applied**: verify NativeWind classes and theme tokens
* **Component not found**: check exports and import paths

## Next Steps

* [File Structure](/mobile/file-structure)
* [Adding Screens](/mobile/adding-screens)

### Import Pattern

Components are imported directly from their files:

```typescript theme={null}
import { AppText } from "@/components/app-text";
import { ScreenContainer } from "@/components/screen-container";
```

### TypeScript Best Practices

```typescript theme={null}
// Define clear interfaces
interface ButtonProps {
  children: React.ReactNode;
  variant: "primary" | "secondary" | "danger";
  size?: "sm" | "md" | "lg";
  disabled?: boolean;
  onPress: () => void; // Required callback
  className?: string; // Optional styling
}

// Use union types for variants
type AlertType = "success" | "warning" | "error" | "info";

// Export types for reuse
export type { ButtonProps, AlertType };
```

## Styling Guidelines

### NativeWind Classes

Use Tailwind CSS classes through NativeWind:

```typescript theme={null}
// Good - Semantic classes
<View className="flex-1 bg-background p-4 gap-2">
  <AppText className="text-2xl font-bold text-foreground">
    Title
  </AppText>
</View>

// Avoid - Arbitrary values
<View style={{ flex: 1, backgroundColor: '#fff', padding: 16 }}>
```

### Theme Integration

Components should respect the theme system:

```typescript theme={null}
import { useTheme } from "heroui-native";

export function ThemedComponent() {
  const { colors, isDark } = useTheme();

  return (
    <View
      className="p-4 rounded-lg"
      style={{
        backgroundColor: isDark ? colors.background : colors.card
      }}
    >
      <AppText className="text-foreground">Themed content</AppText>
    </View>
  );
}
```

### Responsive Design

Handle different screen sizes and form factors:

```typescript theme={null}
import { useResponsive } from "@/components/useResponsive";

export function ResponsiveComponent() {
  const { isTablet } = useResponsive();

  return (
    <View className={`p-4 ${isTablet ? "max-w-md mx-auto" : "w-full"}`}>
      {/* Component content */}
    </View>
  );
}
```

## Copy Organization

Launch does not ship with a centralized copy system. Keep copy close to the
component or feature module it belongs to, and extract shared strings into
constants when needed.

## Testing Components

### Component Testing

```typescript theme={null}
// __tests__/my-component.test.tsx
import { render, fireEvent } from "@testing-library/react-native";
import { MyComponent } from "../my-component";

describe("MyComponent", () => {
  it("renders correctly", () => {
    const { getByText } = render(
      <MyComponent title="Test Title" />
    );

    expect(getByText("Test Title")).toBeTruthy();
  });

  it("handles press events", () => {
    const mockOnPress = jest.fn();
    const { getByText } = render(
      <MyComponent title="Test" onPress={mockOnPress} />
    );

    fireEvent.press(getByText("Test"));
    expect(mockOnPress).toHaveBeenCalled();
  });
});
```

### Visual Testing

Use Storybook or component galleries for visual testing:

```typescript theme={null}
// stories/MyComponent.stories.tsx
export default {
  title: "UI/MyComponent",
  component: MyComponent,
};

export const Primary = {
  args: {
    title: "Primary Button",
    variant: "primary",
  },
};

export const Secondary = {
  args: {
    title: "Secondary Button",
    variant: "secondary",
  },
};
```

## Performance Considerations

### Memoization

Use React.memo for expensive components:

```typescript theme={null}
import React from "react";

interface ExpensiveComponentProps {
  data: ComplexDataType[];
  onItemPress: (id: string) => void;
}

export const ExpensiveComponent = React.memo<ExpensiveComponentProps>(
  ({ data, onItemPress }) => {
    return (
      <View>
        {data.map(item => (
          <ExpensiveItem
            key={item.id}
            item={item}
            onPress={() => onItemPress(item.id)}
          />
        ))}
      </View>
    );
  }
);
```

### Lazy Loading

Use lazy loading for heavy components:

```typescript theme={null}
import { lazy, Suspense } from "react";
import { AppText } from "@/components/app-text";

const HeavyComponent = lazy(() => import("./heavy-component"));

export function ParentComponent() {
  return (
    <Suspense fallback={<AppText>Loading...</AppText>}>
      <HeavyComponent />
    </Suspense>
  );
}
```

## Best Practices

### Component Design

1. **Single Responsibility** - Each component should have one clear purpose
2. **Composition over Inheritance** - Build complex components from simpler ones
3. **Props Interface** - Always define TypeScript interfaces for props
4. **Default Props** - Provide sensible defaults for optional props
5. **Error Boundaries** - Handle errors gracefully

### Code Organization

1. **Logical Grouping** - Place components in appropriate category folders
2. **Index Exports** - Always export from folder index files
3. **Consistent Naming** - Use PascalCase for components, camelCase for props
4. **File Naming** - Use kebab-case for file names

### Documentation

1. **Props Documentation** - Document complex props with JSDoc
2. **Usage Examples** - Provide clear usage examples
3. **Component Stories** - Create Storybook stories for visual components
4. **README Updates** - Keep component documentation current

This component system ensures consistency, reusability, and maintainability across the entire mobile application.
