Buttons
Overview
The Button components library provides a comprehensive set of button components built on top of Chakra UI's Button system. These components offer consistent styling, behavior, and accessibility features while providing specialized functionality for common use cases.
Button Components
Basic Buttons
- Button - Standard Chakra UI button (extended)
- ButtonRightIcon - Button with right-side icon and loading state
- CustomIconButton - Customizable icon button with tooltip
Action Buttons
- WPExportAction - Export functionality button
- WPFilterAction - Filter functionality button
- WPFilteAction - Alternative filter button (typo in name)
Specialized Icon Buttons
- DownloadButton - Download action icon button
- FilterButton - Filter action icon button
When to Use
CustomIconButton
- Use for actions that don't need text labels
- When you need tooltips for icon-only buttons
- For toolbar and compact interfaces
ButtonRightIcon
- Use when you need a button with an icon and loading state
- For primary actions with visual indicators
- When you need consistent loading behavior
WPExportAction
- Use for data export functionality
- When you need consistent export button styling
- For download/export operations
WPFilterAction
- Use for filter functionality
- When you need consistent filter button styling
- For search and filter operations
DownloadButton
- Use specifically for download actions
- When you need a download icon button
- For file download operations
Common Props
Standard Button Props
All button components extend Chakra UI's ButtonProps:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| size | string | - | 'md' | Button size |
| variant | string | - | 'solid' | Button variant |
| colorScheme | string | - | - | Color scheme |
| isDisabled | boolean | - | false | Disabled state |
| isLoading | boolean | - | false | Loading state |
| onClick | function | - | - | Click handler |
| children | ReactNode | - | - | Button content |
Icon Button Props
For icon buttons:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| icon | ReactNode | ✓ | - | Icon element |
| label | string | ✓ | - | Accessibility label |
| size | string | - | 'sm' | Icon button size |
| noTooltip | boolean | - | false | Disable tooltip |
API Documentation
CustomIconButton
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| icon | ReactNode | ✓ | - | Icon element |
| label | string | ✓ | - | Accessibility label and tooltip text |
| size | string | - | 'sm' | Button size |
| noTooltip | boolean | - | false | Disable tooltip |
| variant | string | - | - | Button variant |
Usage Example
import CustomIconButton from 'components/Button/CustomIconButton';
import { EditIcon } from 'components/WPIcons';
function EditButton() {
return (
<CustomIconButton
icon={<EditIcon />}
label='Edit item'
size='md'
variant='outline'
onClick={() => console.log('Edit clicked')}
/>
);
}
ButtonRightIcon
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| text | string | ✓ | - | Button text |
| icon | ReactNode | ✓ | - | Right icon element |
| isLoading | boolean | - | false | Loading state |
| spinnerColor | string | - | 'white' | Loading spinner color |
| loadingText | string | - | '' | Text shown during loading |
Usage Example
import ButtonRightIcon from 'components/Button/ButtonRightIcon';
import { ArrowRightIcon } from 'components/WPIcons';
function SubmitButton() {
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async () => {
setIsLoading(true);
try {
await submitForm();
} finally {
setIsLoading(false);
}
};
return (
<ButtonRightIcon
text='Submit'
icon={<ArrowRightIcon />}
isLoading={isLoading}
loadingText='Submitting...'
onClick={handleSubmit}
/>
);
}
WPExportAction
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| handleClick | function | ✓ | - | Click handler |
| size | string | - | 'sm' | Button size |
Usage Example
import WPExportAction from 'components/Button/WPExportAction';
function ExportButton() {
const handleExport = () => {
// Export logic
console.log('Exporting data...');
};
return <WPExportAction handleClick={handleExport} size='md' />;
}
WPFilterAction
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| handleClick | function | ✓ | - | Click handler |
| size | string | - | 'sm' | Button size |
Usage Example
import WPFilterAction from 'components/Button/WPFilterAction';
function FilterButton() {
const handleFilter = () => {
// Filter logic
console.log('Opening filter...');
};
return <WPFilterAction handleClick={handleFilter} size='md' />;
}
DownloadButton
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| label | string | ✓ | - | Accessibility label and tooltip text |
| size | string | - | 'sm' | Button size |
Usage Example
import DownloadButton from 'components/Button/DownloadButton';
function FileDownloadButton() {
const handleDownload = () => {
// Download logic
console.log('Downloading file...');
};
return (
<DownloadButton label='Download file' size='md' onClick={handleDownload} />
);
}
Button Patterns
Basic Action Button
import { Button } from '@chakra-ui/react';
function BasicButton() {
return (
<Button colorScheme='blue' size='md' onClick={() => console.log('Clicked')}>
Click Me
</Button>
);
}
Loading Button
import { Button } from '@chakra-ui/react';
function LoadingButton() {
const [isLoading, setIsLoading] = useState(false);
const handleClick = async () => {
setIsLoading(true);
try {
await performAction();
} finally {
setIsLoading(false);
}
};
return (
<Button
isLoading={isLoading}
loadingText='Processing...'
colorScheme='green'
onClick={handleClick}
>
Submit
</Button>
);
}
Icon Button with Tooltip
import CustomIconButton from 'components/Button/CustomIconButton';
import { DeleteIcon } from 'components/WPIcons';
function DeleteButton() {
return (
<CustomIconButton
icon={<DeleteIcon />}
label='Delete item'
variant='outline'
colorScheme='red'
onClick={() => console.log('Delete')}
/>
);
}
Button Group
import { ButtonGroup, Button } from '@chakra-ui/react';
function ButtonGroupExample() {
return (
<ButtonGroup spacing='4'>
<Button variant='outline'>Cancel</Button>
<Button colorScheme='blue'>Save</Button>
</ButtonGroup>
);
}
Responsive Button
import { Button } from '@chakra-ui/react';
function ResponsiveButton() {
return (
<Button
size={{ base: 'sm', md: 'md' }}
width={{ base: 'full', md: 'auto' }}
>
Responsive Button
</Button>
);
}
Async Button with Status
import { Button, useToast } from '@chakra-ui/react';
function AsyncButton() {
const [isLoading, setIsLoading] = useState(false);
const toast = useToast();
const handleAsyncAction = async () => {
setIsLoading(true);
try {
await performAsyncAction();
toast({
title: 'Success',
description: 'Action completed successfully',
status: 'success',
duration: 3000,
isClosable: true,
});
} catch (error) {
toast({
title: 'Error',
description: 'Action failed',
status: 'error',
duration: 3000,
isClosable: true,
});
} finally {
setIsLoading(false);
}
};
return (
<Button
isLoading={isLoading}
loadingText='Processing...'
onClick={handleAsyncAction}
colorScheme='green'
>
Async Action
</Button>
);
}
Form Submit Button
import { Button } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
function FormSubmitButton() {
const {
formState: { isSubmitting, isValid },
} = useForm();
return (
<Button
type='submit'
isLoading={isSubmitting}
loadingText='Submitting...'
isDisabled={!isValid}
colorScheme='blue'
>
Submit Form
</Button>
);
}
Button Sizes
Available Sizes
// Extra small
<Button size="xs">Extra Small</Button>
// Small
<Button size="sm">Small</Button>
// Medium (default)
<Button size="md">Medium</Button>
// Large
<Button size="lg">Large</Button>
Custom Sizes
<Button fontSize='18px' px='8' py='4' height='auto'>
Custom Size
</Button>
Button Variants
Solid Buttons
<Button variant='solid' colorScheme='blue'>
Solid Button
</Button>
Outline Buttons
<Button variant='outline' colorScheme='blue'>
Outline Button
</Button>
Ghost Buttons
<Button variant='ghost' colorScheme='blue'>
Ghost Button
</Button>
Link Buttons
<Button variant='link' colorScheme='blue'>
Link Button
</Button>
Button States
Disabled State
<Button isDisabled>Disabled Button</Button>
Loading State
<Button isLoading loadingText='Loading...'>
Loading Button
</Button>
Active State
<Button isActive>Active Button</Button>
Styling & Theming
Color Schemes
// Primary colors
<Button colorScheme="blue">Blue</Button>
<Button colorScheme="green">Green</Button>
<Button colorScheme="red">Red</Button>
// Neutral colors
<Button colorScheme="gray">Gray</Button>
<Button colorScheme="blackAlpha">Black Alpha</Button>
Custom Styling
<Button
bg='gradient(to-r, blue.400, purple.500)'
color='white'
_hover={{
bg: 'gradient(to-r, blue.500, purple.600)',
}}
_active={{
bg: 'gradient(to-r, blue.600, purple.700)',
}}
>
Custom Styled Button
</Button>
Responsive Styling
<Button
colorScheme={{ base: 'blue', md: 'green' }}
size={{ base: 'sm', md: 'md' }}
variant={{ base: 'solid', md: 'outline' }}
>
Responsive Button
</Button>
Button Composition
Button with Left Icon
import { Button } from '@chakra-ui/react';
import { AddIcon } from 'components/WPIcons';
<Button leftIcon={<AddIcon />} colorScheme='green'>
Add Item
</Button>;
Button with Right Icon
import { Button } from '@chakra-ui/react';
import { ExternalLinkIcon } from 'components/WPIcons';
<Button rightIcon={<ExternalLinkIcon />} colorScheme='blue'>
External Link
</Button>;
Icon-only Button
import { IconButton } from '@chakra-ui/react';
import { HamburgerIcon } from 'components/WPIcons';
<IconButton
aria-label='Open menu'
icon={<HamburgerIcon />}
variant='outline'
/>;
Accessibility
ARIA Support
- All buttons include proper ARIA labels
- Icon buttons have descriptive labels
- Loading states are announced to screen readers
- Disabled states are properly communicated
Keyboard Navigation
- Space and Enter keys activate buttons
- Tab navigation between buttons
- Focus indicators are visible
- Disabled buttons are skipped in tab order
Screen Reader Support
- Button purpose is clearly announced
- Loading states are communicated
- Error states are accessible
- Success feedback is provided
Testing
Unit Testing
import { render, screen, fireEvent } from '@testing-library/react';
import CustomIconButton from 'components/Button/CustomIconButton';
import { EditIcon } from 'components/WPIcons';
test('renders button with correct label', () => {
const onClick = jest.fn();
render(
<CustomIconButton
icon={<EditIcon />}
label='Edit item'
onClick={onClick}
/>,
);
const button = screen.getByRole('button', { name: 'Edit item' });
expect(button).toBeInTheDocument();
fireEvent.click(button);
expect(onClick).toHaveBeenCalled();
});
Integration Testing
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import ButtonRightIcon from 'components/Button/ButtonRightIcon';
test('shows loading state correctly', async () => {
const onClick = jest.fn().mockResolvedValue(undefined);
render(
<ButtonRightIcon
text='Submit'
icon={<div>Icon</div>}
loadingText='Submitting...'
onClick={onClick}
/>,
);
const button = screen.getByRole('button', { name: 'Submit' });
fireEvent.click(button);
await waitFor(() => {
expect(screen.getByText('Submitting...')).toBeInTheDocument();
});
});
Performance Optimization
Memoization
import { memo } from 'react';
import { Button } from '@chakra-ui/react';
const MemoizedButton = memo(({ children, ...props }) => (
<Button {...props}>{children}</Button>
));
Lazy Loading
import { lazy, Suspense } from 'react';
const LazyButton = lazy(() => import('components/Button/CustomIconButton'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyButton icon={<EditIcon />} label='Edit' />
</Suspense>
);
}
Common Issues
Button Not Clicking
- Check if button is disabled
- Verify onClick handler is attached
- Ensure button is not covered by other elements
- Check for preventDefault() calls
Styling Issues
- Verify theme configuration
- Check for conflicting CSS
- Ensure proper color scheme usage
- Test responsive behavior
Loading State Issues
- Check loading state management
- Verify loading text is provided
- Ensure loading state is reset
- Test error handling
Best Practices
- Consistent Sizing: Use theme sizes consistently across the application
- Meaningful Labels: Provide clear, descriptive labels for icon buttons
- Loading States: Always provide feedback during async operations
- Keyboard Support: Ensure all buttons are keyboard accessible
- Color Contrast: Maintain sufficient contrast ratios
- Responsive Design: Test buttons on different screen sizes
- Error Handling: Provide appropriate error feedback
- Performance: Use memoization for expensive button components
Migration Guide
From Standard Button to Custom Components
// Before
<Button onClick={handleClick}>
Export Data
</Button>
// After
<WPExportAction handleClick={handleClick} />
From Icon Button to Custom Icon Button
// Before
<IconButton
aria-label="Edit"
icon={<EditIcon />}
onClick={handleEdit}
/>
// After
<CustomIconButton
icon={<EditIcon />}
label="Edit"
onClick={handleEdit}
/>
Button Loading States
// Before
<Button isLoading={isLoading}>
{isLoading ? 'Loading...' : 'Submit'}
</Button>
// After
<Button
isLoading={isLoading}
loadingText="Loading..."
>
Submit
</Button>
TypeScript Support
Button Props Interface
interface CustomButtonProps extends ButtonProps {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'sm' | 'md' | 'lg';
isLoading?: boolean;
loadingText?: string;
}
const CustomButton: React.FC<CustomButtonProps> = ({
variant = 'primary',
size = 'md',
isLoading = false,
loadingText = 'Loading...',
children,
...props
}) => {
return (
<Button
variant={variant}
size={size}
isLoading={isLoading}
loadingText={loadingText}
{...props}
>
{children}
</Button>
);
};
Icon Button Props
interface IconButtonProps {
icon: React.ReactNode;
label: string;
size?: 'sm' | 'md' | 'lg';
variant?: string;
onClick?: () => void;
isDisabled?: boolean;
noTooltip?: boolean;
}
This completes the comprehensive documentation for the Button components in the WorkPayCore frontend application.