Skip to main content

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:

PropTypeRequiredDefaultDescription
sizestring-'md'Button size
variantstring-'solid'Button variant
colorSchemestring--Color scheme
isDisabledboolean-falseDisabled state
isLoadingboolean-falseLoading state
onClickfunction--Click handler
childrenReactNode--Button content

Icon Button Props​

For icon buttons:

PropTypeRequiredDefaultDescription
iconReactNode✓-Icon element
labelstring✓-Accessibility label
sizestring-'sm'Icon button size
noTooltipboolean-falseDisable tooltip

API Documentation​

CustomIconButton​

Props​

PropTypeRequiredDefaultDescription
iconReactNode✓-Icon element
labelstring✓-Accessibility label and tooltip text
sizestring-'sm'Button size
noTooltipboolean-falseDisable tooltip
variantstring--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​

PropTypeRequiredDefaultDescription
textstring✓-Button text
iconReactNode✓-Right icon element
isLoadingboolean-falseLoading state
spinnerColorstring-'white'Loading spinner color
loadingTextstring-''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​

PropTypeRequiredDefaultDescription
handleClickfunction✓-Click handler
sizestring-'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​

PropTypeRequiredDefaultDescription
handleClickfunction✓-Click handler
sizestring-'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​

PropTypeRequiredDefaultDescription
labelstring✓-Accessibility label and tooltip text
sizestring-'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>
<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​

  1. Consistent Sizing: Use theme sizes consistently across the application
  2. Meaningful Labels: Provide clear, descriptive labels for icon buttons
  3. Loading States: Always provide feedback during async operations
  4. Keyboard Support: Ensure all buttons are keyboard accessible
  5. Color Contrast: Maintain sufficient contrast ratios
  6. Responsive Design: Test buttons on different screen sizes
  7. Error Handling: Provide appropriate error feedback
  8. 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&lt;CustomButtonProps&gt; = ({
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.