--- 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 ); } ``` ### 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