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.