---
name: component-creation
description: Creates React components following RYLA patterns and file organization. Use when creating components, building UI, implementing features, or when the user mentions components, UI, or React.
---
# Component Creation
Creates React components following RYLA patterns, file organization, and best practices.
## Quick Start
When creating a component:
1. **Determine Type** - Page, Feature, or UI component
2. **Choose Location** - Page-specific or shared
3. **Create File** - Follow naming conventions
4. **Implement Component** - Server Component by default
5. **Extract if Needed** - Extract when > 150 lines
## Component Types
### Page Component
**Location**: `apps/web/app/[route]/page.tsx`
**Responsibilities:**
- Data fetching (Server Component or useEffect)
- Layout composition
- Error boundaries
- NO business logic
**Example:**
```tsx
// app/characters/page.tsx
import { getCharacters } from '@ryla/data';
import { CharacterList } from './components/CharacterList';
export default async function CharactersPage() {
// Fetch data on server
const characters = await getCharacters();
return (
Characters
);
}
```
### Feature Component
**Location**: `apps/web/components/[feature]/` or `app/[route]/components/`
**Responsibilities:**
- Orchestrates UI + logic
- 100-200 lines target
- Can be Server or Client Component
**Example:**
```tsx
// components/character-wizard/CharacterWizard.tsx
'use client';
import { useState } from 'react';
import { WizardSteps } from './components/WizardSteps';
import { useCharacterWizard } from './hooks/useCharacterWizard';
export function CharacterWizard() {
const { currentStep, nextStep, prevStep, wizardState } = useCharacterWizard();
return (
{/* Wizard content */}
);
}
```
### UI Component
**Location**: `libs/ui/src/components/` or `components/ui/`
**Responsibilities:**
- Pure presentation
- Props in, JSX out
- < 80 lines target
- Reusable across apps
**Example:**
```tsx
// libs/ui/src/components/ryla-button.tsx
import { Button } from '@radix-ui/react-button';
export interface RylaButtonProps {
children: React.ReactNode;
variant?: 'primary' | 'secondary';
onClick?: () => void;
}
export function RylaButton({
children,
variant = 'primary',
onClick,
}: RylaButtonProps) {
return (
);
}
```
## Server vs Client Components
### Server Component (Default)
**Use when:**
- Fetching data
- Accessing backend resources
- No interactivity needed
- Better performance
```tsx
// ✅ Good: Server Component (default)
// app/characters/page.tsx
import { getCharacters } from '@ryla/data';
export default async function CharactersPage() {
const characters = await getCharacters();
return ;
}
```
### Client Component
**Use when:**
- Need interactivity (onClick, onChange)
- Using hooks (useState, useEffect)
- Browser APIs (localStorage, window)
- Event listeners
```tsx
// ✅ Good: Client Component for interactivity
'use client';
import { useState } from 'react';
export function CharacterCard({ character }: { character: Character }) {
const [isFavorite, setIsFavorite] = useState(false);
return (