rn-button-component
π―Skillfrom jchaselubitz/drill-app
Creates reusable, customizable React Native button components with consistent styling and interaction patterns for mobile app interfaces
Installation
npx skills add https://github.com/jchaselubitz/drill-app --skill rn-button-componentSkill Details
Ensures buttons use the unified Button component with proper state management, icon support, and glass effect integration. Apply when creating or modifying buttons in the app.
Overview
# Button Component
Guide for using the unified Button component with state management, icon support, and glass effect integration.
Overview
- Location:
@/components/Button - Features: State management, icon support, loading states, success/error states, glass effect on iOS
- Design: Rounded corners (borderRadius: 25), glass effect on iOS when available
Basic Usage
```tsx
import { Button } from '@/components/Button';
```
Props
Required Props
text: string | React.ReactNode- Button label textonPress: () => void- Press handler function
Optional Props
variant?: 'primary' | 'secondary' | 'destructive'- Button style variant (default:'primary')buttonState?: ButtonState- Current button state (default:'default')loadingText?: string | React.ReactNode- Text shown during loading statesuccessText?: string | React.ReactNode- Text shown during success stateerrorText?: string | React.ReactNode- Text shown during error stateicon?: { name, size?, position? }- Icon configurationsuccessIcon?: { name, size? }- Icon shown in success state (default:'checkmark')reset?: boolean- Auto-reset from success to default after 2 seconds (default:false)setButtonState?: (state: ButtonState) => void- External state control functionstyle?: StyleProp- Additional styles
Button States
```tsx
export type ButtonState = 'default' | 'disabled' | 'loading' | 'success' | 'error';
```
State Behavior
'default': Normal interactive state'disabled': Button is disabled and non-interactive'loading': Shows loading spinner with optionalloadingText'success': Shows success icon with optionalsuccessText'error': Shows error message witherrorText
Common Patterns
Basic Button
```tsx
```
Button with Variant
```tsx
```
Loading State
```tsx
const [isSaving, setIsSaving] = useState(false);
text="Save"
onPress={handleSave}
buttonState={isSaving ? 'loading' : 'default'}
loadingText="Saving..."
/>
```
Disabled State
```tsx
text="Submit"
onPress={handleSubmit}
buttonState={!isValid ? 'disabled' : 'default'}
/>
```
Button with Icon
```tsx
text="Create Lesson"
onPress={handleCreate}
icon={{ name: 'add', size: 24, position: 'left' }}
variant="secondary"
/>
```
Success State with Auto-Reset
```tsx
const [buttonState, setButtonState] = useState
const handleSave = async () => {
setButtonState('loading');
try {
await saveData();
setButtonState('success');
} catch (error) {
setButtonState('error');
}
};
text="Save"
onPress={handleSave}
buttonState={buttonState}
setButtonState={setButtonState}
loadingText="Saving..."
successText="Saved!"
errorText="Failed to save"
reset={true} // Auto-resets to 'default' after 2 seconds
/>
```
Combined Loading and Disabled
```tsx
text="Save Lesson"
onPress={handleSave}
buttonState={isSaving ? 'loading' : isLoading ? 'disabled' : 'default'}
loadingText="Saving..."
/>
```
Icon Configuration
Icon Props
```tsx
icon?: {
name: keyof typeof Ionicons.glyphMap; // Required: Ionicons icon name
size?: number; // Optional: Icon size (default: 24)
position?: 'left' | 'right'; // Optional: Icon position (default: 'left')
}
```
Examples
```tsx
// Left icon (default)
text="Add Item"
icon={{ name: 'add', position: 'left' }}
onPress={handleAdd}
/>
// Right icon
text="Next"
icon={{ name: 'arrow-forward', position: 'right' }}
onPress={handleNext}
/>
// Custom size
text="Settings"
icon={{ name: 'settings', size: 20 }}
onPress={handleSettings}
/>
```
State Management
Internal State (Default)
The button manages its own state internally when setButtonState is not provided:
```tsx
text="Click Me"
onPress={handleClick}
buttonState="loading" // State is managed internally
/>
```
External State Control
Provide setButtonState to control state externally:
```tsx
const [state, setState] = useState
text="Submit"
onPress={handleSubmit}
buttonState={state}
setButtonState={setState}
loadingText="Submitting..."
/>
```
Auto-Reset Pattern
When reset={true} and button reaches 'success' state, it automatically resets to 'default' after 2 seconds:
```tsx
const [state, setState] = useState
text="Save"
onPress={async () => {
setState('loading');
await save();
setState('success');
}}
buttonState={state}
setButtonState={setState}
reset={true}
successText="Saved!"
/>
```
Glass Effect
The button automatically uses glass effect on iOS when available:
- iOS 26+: Uses
GlassViewwith liquid glass effect - Other platforms: Falls back to regular
Viewwith background color - Automatic: No configuration needed, handled internally
The glass effect respects:
variantprop for tint colorbuttonStatefor disabled/loading tint- Interactive glass effect enabled automatically
Styling
Default Styles
borderRadius: 25- Fully rounded cornerspaddingVertical: 14paddingHorizontal: 24minHeight: 48
Custom Styles
```tsx
text="Custom Button"
onPress={handlePress}
style={{ marginTop: 16, width: '100%' }}
/>
```
Complete Examples
Form Submit Button
```tsx
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitState, setSubmitState] = useState
const handleSubmit = async () => {
setIsSubmitting(true);
setSubmitState('loading');
try {
await submitForm();
setSubmitState('success');
} catch (error) {
setSubmitState('error');
} finally {
setIsSubmitting(false);
}
};
text="Submit Form"
onPress={handleSubmit}
buttonState={submitState}
setButtonState={setSubmitState}
loadingText="Submitting..."
successText="Submitted!"
errorText="Submission failed"
reset={true}
disabled={!isFormValid}
/>
```
Action Button with Icon
```tsx
text="Create Lesson"
onPress={openModal}
icon={{ name: 'add', size: 24, position: 'left' }}
variant="secondary"
/>
```
Conditional Loading
```tsx
text="Translate"
onPress={handleTranslate}
buttonState={isTranslating ? 'loading' : 'default'}
loadingText="Translating..."
variant="secondary"
/>
```
Best Practices
- Always provide
loadingTextwhen using loading state for better UX - Use
setButtonStatefor complex state management scenarios - Use
reset={true}for temporary success states (e.g., form submissions) - Provide
errorTextwhen handling error states - Use icons sparingly - only when they add clarity
- Choose appropriate variants - use
destructiveonly for destructive actions
TypeScript
```tsx
import { Button, ButtonState } from '@/components/Button';
const [state, setState] = useState
```
References
- Component location:
components/Button.tsx - Uses:
expo-glass-effect,@expo/vector-icons, React NativePressable