Claude
Skills
Sign in
Back

gluestack-ui-v4:creating-components

Included with Lifetime
$97 forever

Step-by-step guide for creating components with gluestack-ui v4 - covers planning, structure, styling, TypeScript, and common component patterns.

Design

What this skill does


# Gluestack UI v4 - Creating Components

This sub-skill provides practical guidance for creating new components using gluestack-ui v4, from planning to implementation.

## Component Creation Workflow

### Step 1: Plan Component Structure

Before writing code, answer these questions:

1. **What is the component's purpose?**
   - Form input, data display, navigation, layout, etc.

2. **Which Gluestack components do I need?**
   - Check official docs: `https://v4.gluestack.io/ui/docs/components/${componentName}/`
   - Use Gluestack wrappers, not React Native primitives

3. **Does it need compound components?**
   - Multiple related sub-components (Header, Body, Footer)
   - Icon + Text combinations
   - Label + Input patterns

4. **What props should it accept?**
   - Size variants: `sm`, `md`, `lg`
   - Visual variants: `default`, `outline`, `ghost`
   - State props: `isDisabled`, `isInvalid`, `isLoading`
   - Custom className for overrides

5. **Does it need variants?**
   - If yes, use `tva` (Tailwind Variant Authority)
   - Define base styles and variant options

### Step 2: Check Official Documentation

**ALWAYS** verify component usage before creating:

```bash
# Visit official docs for the component
https://v4.gluestack.io/ui/docs/components/${componentName}/
```

Check for:
- Latest API and props
- Required sub-components
- Usage examples
- Accessibility features

### Step 3: Create Component File

Follow this file structure:

```
components/
├── ui/                      # Gluestack UI components (copy-paste)
│   ├── box/
│   ├── button/
│   └── input/
└── custom/                  # Your custom components
    ├── profile-card/
    │   └── index.tsx
    └── login-form/
        └── index.tsx
```

## Component Templates

### Template 1: Simple Component (No Variants)

Use when component has consistent styling without variants.

```tsx
import React from 'react';
import { Box } from '@/components/ui/box';
import { Text } from '@/components/ui/text';
import { Heading } from '@/components/ui/heading';

interface ProfileCardProps {
  readonly name: string;
  readonly email: string;
  readonly className?: string;
}

export const ProfileCard = ({ name, email, className }: ProfileCardProps) => {
  return (
    <Box className={`bg-card rounded-lg border border-border p-4 ${className || ''}`}>
      <Heading size="lg" className="text-card-foreground">
        {name}
      </Heading>
      <Text size="sm" className="text-muted-foreground mt-1">
        {email}
      </Text>
    </Box>
  );
};
```

**Key points:**
- ✅ Uses Gluestack components (Box, Text, Heading)
- ✅ TypeScript interface with `readonly` props
- ✅ Semantic tokens (bg-card, text-card-foreground)
- ✅ Accepts className for customization
- ✅ Component props for sizing (Heading size)

### Template 2: Component with Variants (Using tva)

Use when component needs multiple visual styles or sizes.

```tsx
import React from 'react';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { Box } from '@/components/ui/box';
import { Text } from '@/components/ui/text';

interface AlertProps {
  readonly variant?: 'default' | 'success' | 'warning' | 'destructive';
  readonly size?: 'sm' | 'md' | 'lg';
  readonly className?: string;
  readonly children: React.ReactNode;
}

const alertStyles = tva({
  base: 'rounded-lg border p-4',
  variants: {
    variant: {
      default: 'bg-card border-border',
      success: 'bg-primary/10 border-primary',
      warning: 'bg-accent/10 border-accent',
      destructive: 'bg-destructive/10 border-destructive',
    },
    size: {
      sm: 'p-2',
      md: 'p-4',
      lg: 'p-6',
    },
  },
  defaultVariants: {
    variant: 'default',
    size: 'md',
  },
});

const alertTextStyles = tva({
  base: 'font-sans',
  parentVariants: {
    variant: {
      default: 'text-foreground',
      success: 'text-primary',
      warning: 'text-accent-foreground',
      destructive: 'text-destructive',
    },
    size: {
      sm: 'text-xs',
      md: 'text-sm',
      lg: 'text-base',
    },
  },
});

export const Alert = ({ variant, size, className, children }: AlertProps) => {
  return (
    <Box className={alertStyles({ variant, size, class: className })}>
      <Text className={alertTextStyles({ parentVariants: { variant, size } })}>
        {children}
      </Text>
    </Box>
  );
};
```

**Key points:**
- ✅ Uses tva for variant management
- ✅ Base styles + variant options
- ✅ Default variants specified
- ✅ Parent variants for child components
- ✅ className override support

### Template 3: Compound Component Pattern

Use when component has multiple related sub-components.

```tsx
import React from 'react';
import { Box } from '@/components/ui/box';
import { Heading } from '@/components/ui/heading';
import { Text } from '@/components/ui/text';
import { HStack } from '@/components/ui/hstack';

// Main Card Component
interface CardProps {
  readonly className?: string;
  readonly children: React.ReactNode;
}

export const Card = ({ className, children }: CardProps) => {
  return (
    <Box className={`bg-card rounded-lg border border-border shadow-sm ${className || ''}`}>
      {children}
    </Box>
  );
};

// Card Header Sub-component
interface CardHeaderProps {
  readonly className?: string;
  readonly children: React.ReactNode;
}

export const CardHeader = ({ className, children }: CardHeaderProps) => {
  return (
    <Box className={`p-4 border-b border-border ${className || ''}`}>
      {children}
    </Box>
  );
};

// Card Body Sub-component
interface CardBodyProps {
  readonly className?: string;
  readonly children: React.ReactNode;
}

export const CardBody = ({ className, children }: CardBodyProps) => {
  return (
    <Box className={`p-4 ${className || ''}`}>
      {children}
    </Box>
  );
};

// Card Footer Sub-component
interface CardFooterProps {
  readonly className?: string;
  readonly children: React.ReactNode;
}

export const CardFooter = ({ className, children }: CardFooterProps) => {
  return (
    <HStack space="md" className={`p-4 border-t border-border ${className || ''}`}>
      {children}
    </HStack>
  );
};

// Usage
// <Card>
//   <CardHeader>
//     <Heading size="lg">Title</Heading>
//   </CardHeader>
//   <CardBody>
//     <Text>Content</Text>
//   </CardBody>
//   <CardFooter>
//     <Button>Action</Button>
//   </CardFooter>
// </Card>
```

**Key points:**
- ✅ Main component + sub-components
- ✅ Each sub-component is independent
- ✅ Consistent styling across sub-components
- ✅ Flexible composition

### Template 4: Form Component

Use for form inputs with labels, validation, and error messages.

```tsx
import React, { useState } from 'react';
import { FormControl, FormControlLabel, FormControlLabelText } from '@/components/ui/form-control';
import { FormControlError, FormControlErrorIcon, FormControlErrorText } from '@/components/ui/form-control';
import { FormControlHelper, FormControlHelperText } from '@/components/ui/form-control';
import { Input, InputField, InputSlot, InputIcon } from '@/components/ui/input';
import { MailIcon, AlertCircleIcon } from '@/components/ui/icon';

interface EmailInputProps {
  readonly label?: string;
  readonly placeholder?: string;
  readonly helperText?: string;
  readonly value: string;
  readonly error?: string;
  readonly onChange: (value: string) => void;
  readonly className?: string;
}

export const EmailInput = ({
  label = 'Email Address',
  placeholder = 'Enter your email',
  helperText,
  value,
  error,
  onChange,
  className,
}: EmailInputProps) => {
  const [isFocused, setIsFocused] = useState(false);

  return (
    <FormControl isInvalid={!!error} className={className}>
      <FormControlLabel>
        <FormControlLabelText>{label}</FormControlLabelText>
      </FormControlLabel>

      <Input>
        <InputSlot>
          <InputIcon
            as={MailIcon}
            className={isFocused ? 'text-primary' : 'text-muted-foreground'}
          />
        </InputSlot>
        <InputF

Related in Design