---
name: gluestack-components
description: Use when building UI with gluestack-ui components. Covers component composition, variants, sizes, states, accessibility props, and platform-specific considerations for React and React Native.
allowed-tools:
- Read
- Write
- Edit
- Bash
- Grep
- Glob
---
# gluestack-ui - Components
Expert knowledge of gluestack-ui's universal component library for building accessible, performant UI across React and React Native platforms.
## Overview
gluestack-ui provides 50+ unstyled, accessible components that work seamlessly on web and mobile. Components are copy-pasteable into your project and styled with NativeWind (Tailwind CSS for React Native).
## Key Concepts
### Component Installation
Add components using the CLI:
```bash
# Initialize gluestack-ui in your project
npx gluestack-ui init
# Add individual components
npx gluestack-ui add button
npx gluestack-ui add input
npx gluestack-ui add modal
# Add multiple components
npx gluestack-ui add button input select modal
# Add all components
npx gluestack-ui add --all
```
### Component Anatomy
Every gluestack-ui component follows a consistent pattern:
```tsx
import { Button, ButtonText, ButtonSpinner, ButtonIcon } from '@/components/ui/button';
// Components are composable with sub-components
```
### Variants, Sizes, and Actions
Components support consistent prop APIs:
```tsx
// Button variants
// Button sizes
// Button actions (semantic colors)
```
## Core Components
### Button
Interactive button with loading states and icons:
```tsx
import { Button, ButtonText, ButtonSpinner, ButtonIcon } from '@/components/ui/button';
import { SaveIcon } from 'lucide-react-native';
function SaveButton({ isLoading, onPress }: { isLoading: boolean; onPress: () => void }) {
return (
);
}
```
### Input
Text input with labels and validation:
```tsx
import {
FormControl,
FormControlLabel,
FormControlLabelText,
FormControlHelper,
FormControlHelperText,
FormControlError,
FormControlErrorIcon,
FormControlErrorText,
} from '@/components/ui/form-control';
import { Input, InputField, InputSlot, InputIcon } from '@/components/ui/input';
import { AlertCircleIcon, MailIcon } from 'lucide-react-native';
function EmailInput({ value, onChange, error }: {
value: string;
onChange: (text: string) => void;
error?: string;
}) {
return (
Email
{error ? (
{error}
) : (
We'll never share your email
)}
);
}
```
### Select
Dropdown selection component:
```tsx
import {
Select,
SelectTrigger,
SelectInput,
SelectIcon,
SelectPortal,
SelectBackdrop,
SelectContent,
SelectDragIndicatorWrapper,
SelectDragIndicator,
SelectItem,
} from '@/components/ui/select';
import { ChevronDownIcon } from 'lucide-react-native';
function CountrySelect({ value, onValueChange }: {
value: string;
onValueChange: (value: string) => void;
}) {
return (
);
}
```
### Modal
Dialog overlay component:
```tsx
import {
Modal,
ModalBackdrop,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
ModalFooter,
} from '@/components/ui/modal';
import { Heading } from '@/components/ui/heading';
import { Text } from '@/components/ui/text';
import { Button, ButtonText } from '@/components/ui/button';
import { CloseIcon, Icon } from '@/components/ui/icon';
function ConfirmModal({ isOpen, onClose, onConfirm, title, message }: {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
title: string;
message: string;
}) {
return (
{title}
{message}
);
}
```
### Toast
Notification component:
```tsx
import {
Toast,
ToastTitle,
ToastDescription,
useToast,
} from '@/components/ui/toast';
function NotificationExample() {
const toast = useToast();
const showToast = () => {
toast.show({
placement: 'top',
render: ({ id }) => (
Success!
Your changes have been saved.
),
});
};
return (
);
}
```
### Accordion
Expandable content sections:
```tsx
import {
Accordion,
AccordionItem,
AccordionHeader,
AccordionTrigger,
AccordionTitleText,
AccordionIcon,
AccordionContent,
AccordionContentText,
} from '@/components/ui/accordion';
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react-native';
function FAQAccordion({ items }: { items: { question: string; answer: string }[] }) {
return (
{items.map((item, index) => (
{({ isExpanded }) => (
<>
{item.question}
>
)}
{item.answer}
))}
);
}
```
### Checkbox and Radio
Selection controls:
```tsx
import {
Checkbox,
CheckboxIndicator,
CheckboxIcon,
CheckboxLabel,
} from '@/components/ui/checkbox';
import {
RadioGroup,
Radio,
RadioIndicator,
RadioIcon,
RadioLabel,
} from '@/components/ui/radio';
import { CheckIcon, CircleIcon } from 'lucide-react-native';
function TermsCheckbox({ isChecked, onChange }: {
isChecked: boolean;
onChange: (checked: boolean) => void;
}) {
return (
I agree to the terms and conditions
);
}
function ShippingOptions({ value, onChange }: {
value: string;
onChange: (value: string) => void;
}) {
return (
Standard Shipping (5-7 days)
Express Shipping (2-3 days)
Overnight Shipping (1 day)
);
}
```
## Best Practices
### 1. Use Composition Over Configuration
Compose components with sub-components for flexibility:
```tsx
// Good: Composable structure
// Avoid: Prop-heavy configuration
```
### 2. Leverage FormControl for Form Fields
Wrap inputs in FormControl for consistent validation:
```tsx
Password
{error}
```
### 3. Handle Platform Differences
Use platform-specific logic when needed:
```tsx
import { Platform } from 'react-native';
function ResponsiveModal({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
### 4. Use Proper Loading States
Show loading feedback for async operations:
```tsx
function SubmitButton({ isLoading, onPress }: {
isLoading: boolean;
onPress: () => void;
}) {
return (
);
}
```
### 5. Create Reusable Component Wrappers
Build app-specific components on top of gluestack-ui:
```tsx
// components/app/PrimaryButton.tsx
import { Button, ButtonText, ButtonSpinner } from '@/components/ui/button';
interface PrimaryButtonProps {
children: string;
isLoading?: boolean;
onPress: () => void;
}
export function PrimaryButton({ children, isLoading, onPress }: PrimaryButtonProps) {
return (
);
}
```
## Common Patterns
### Form with Validation
```tsx
import { useState } from 'react';
import { VStack } from '@/components/ui/vstack';
import { Button, ButtonText } from '@/components/ui/button';
import { FormControl, FormControlError, FormControlErrorText } from '@/components/ui/form-control';
import { Input, InputField } from '@/components/ui/input';
interface FormData {
email: string;
password: string;
}
interface FormErrors {
email?: string;
password?: string;
}
function LoginForm({ onSubmit }: { onSubmit: (data: FormData) => void }) {
const [formData, setFormData] = useState({ email: '', password: '' });
const [errors, setErrors] = useState({});
const validate = (): boolean => {
const newErrors: FormErrors = {};
if (!formData.email) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Invalid email format';
}
if (!formData.password) {
newErrors.password = 'Password is required';
} else if (formData.password.length < 8) {
newErrors.password = 'Password must be at least 8 characters';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = () => {
if (validate()) {
onSubmit(formData);
}
};
return (
setFormData({ ...formData, email: text })}
/>
{errors.email}
setFormData({ ...formData, password: text })}
/>
{errors.password}
);
}
```
### Data List with Actions
```tsx
import { HStack } from '@/components/ui/hstack';
import { VStack } from '@/components/ui/vstack';
import { Box } from '@/components/ui/box';
import { Text } from '@/components/ui/text';
import { Heading } from '@/components/ui/heading';
import { Button, ButtonIcon } from '@/components/ui/button';
import { Pressable } from '@/components/ui/pressable';
import { TrashIcon, EditIcon } from 'lucide-react-native';
interface Item {
id: string;
title: string;
description: string;
}
function ItemList({ items, onEdit, onDelete }: {
items: Item[];
onEdit: (id: string) => void;
onDelete: (id: string) => void;
}) {
return (
{items.map((item) => (
{item.title}
{item.description}
))}
);
}
```
## Anti-Patterns
### Do Not Mix Styling Approaches
```tsx
// Bad: Mixing inline styles with NativeWind
// Good: Use NativeWind classes consistently
```
### Do Not Skip Accessibility Props
```tsx
// Bad: Missing accessibility information
// Good: Include accessibility props
```
### Do Not Ignore Platform Constraints
```tsx
// Bad: Using web-only APIs on native
{/* onClick doesn't work on native */}
...
// Good: Use cross-platform events
...
```
### Do Not Hardcode Colors
```tsx
// Bad: Hardcoded colors
Hello
// Good: Use theme tokens
Hello
```
## Related Skills
- **gluestack-theming**: Customizing themes and design tokens
- **gluestack-accessibility**: Ensuring accessible implementations