This component is an example of Atomic Design composition. The Button molecule is built from smaller atoms (Icon and Label) and receives its behavior and appearance through props.
Imports
import type { ButtonInterface } from './Button.interface'
Imports the TypeScript interface that defines the props the component accepts.
import { ButtonSizes, ButtonTypes, IconSizes, LabelTypes } from '@/components/_types_'
Imports enums that provide predefined values for button types, sizes, icon sizes, and label types. Using enums prevents invalid values and improves consistency.
import { Icon, Label } from '@/components/atoms'
Imports two atomic components used to build the button.
Component Definition
const Button = ({ testID, type, size, icon, text, action, disabled }: ButtonInterface) => {
The component receives its properties through destructuring.
Example:
<Button
text="Save"
icon="save"
type={ButtonTypes.PRIMARY}
size={ButtonSizes.MEDIUM}
action={saveData}
/>
Event Handler
const __handleAction = () => action && action()
Executes the supplied callback if it exists.
Equivalent to:
if (action) {
action()
}
When the button is clicked, this function triggers the action.
Rendering the Icon
const __renderIcon = () => icon && <Icon icon={icon} />
Conditionally renders an icon.
If:
icon="save"
it produces:
<Icon icon="save" />
If no icon is provided, nothing is rendered.
Rendering the Text
const __renderText = () => text && <Label text={text} type={LabelTypes.BUTTON} />
Conditionally renders a label.
If:
text="Save"
it produces:
<Label text="Save" type={LabelTypes.BUTTON} />
This keeps text styling centralized inside the Label atom.
Rendering the "Next" Arrow
const __renderNext = () => {
if (type === ButtonTypes.NEXT) {
return <Icon icon={'arrowRight'} size={IconSizes.LARGE} />
}
}
Adds an arrow icon only when the button type is NEXT.
Example:
<Button
text="Continue"
type={ButtonTypes.NEXT}
/>
Produces:
Continue →
Rendered Markup
<div
data-testid={testID}
data-object-type={type ?? ButtonTypes.PRIMARY}
data-object-size={size ?? ButtonSizes.MEDIUM}
data-disabled={disabled ? 'true' : 'false'}
className={`Button`}
onClick={() => __handleAction()}
>
data-testid
Used by testing frameworks:
<div data-testid="button-save">
Allows automated tests to find the element.
data-object-type
Stores the button type.
Example:
<div data-object-type="primary">
Useful for CSS selectors or debugging.
data-object-size
Stores the button size.
Example:
<div data-object-size="large">
Allows styling such as:
.Button[data-object-size='large'] {
padding: 1rem 2rem;
}
data-disabled
Stores disabled state.
Example:
<div data-disabled="true">
className
className="Button"
Provides the base CSS class.
Click Handler
onClick={() => __handleAction()}
Calls the action when the button is clicked.
A simpler version would be:
onClick={__handleAction}
Children
{__renderIcon()}
{__renderText()}
{__renderNext()}
The button is assembled from three optional parts:
- Custom icon
- Label text
- Next-arrow icon
Depending on the props, different combinations appear.
Atomic Design Classification
| Component | Atomic Level | Reason |
|---|---|---|
Icon | Atom | Smallest reusable UI element |
Label | Atom | Smallest reusable text element |
Button | Molecule | Combines multiple atoms into one interaction |
The component demonstrates a core Atomic Design principle: compose larger UI elements from smaller reusable building blocks rather than mixing raw HTML and styling directly into higher-level components.