Articles by Adam Davarel from Notion
Atomic Design is a methodology for creating design systems by breaking down UI components into smaller, reusable parts. It’s divided into five levels: Atoms, Molecules, Organisms, Templates, and Pages. Each level builds on the previous one, promoting modularity and reusability. Here's how you can apply Atomic Design principles to component creation:
Definition: The smallest possible components, such as buttons, input fields, labels, or icons.
Best Practices:
aria-labels
, keyboard navigability). See the Accessibility Best Practice<Button>
, <Input>
, <Icon>
.Example component code :
const Button = ({ label, onClick, isLoading, isDisabled, variant = 'primary' }) => {
const baseClass = 'px-4 py-2 rounded-lg font-semibold text-white transition-colors';
const variantClass = variant === 'secondary' ? 'bg-gray-500 hover:bg-gray-600' : 'bg-blue-500 hover:bg-blue-600';
return (
<button
onClick={onClick}
disabled={isDisabled || isLoading}
className={`${baseClass} ${isDisabled ? 'bg-gray-400 cursor-not-allowed' : variantClass}
${isLoading ? 'bg-blue-300 cursor-wait' : ''}`}
>
{isLoading ? 'Loading...' : label}
</button>
);
};
Definition: Combinations of atoms that work together to form simple components.
Best Practices:
<SearchBar>
(a combination of an input and a button), <FormField>
(label + input).Example component code :
// FormField.js (Molecule)
import React from 'react';
import InputField from './InputField'; // Atom
import Label from './Label'; // Atom
const FormField = ({ label, type, name, value, onChange, isDisabled }) => {
return (
<div className="mb-4">
<Label htmlFor={name}>{label}</Label>
<InputField
type={type}
name={name}
value={value}
onChange={onChange}
isDisabled={isDisabled}
/>
</div>
);
};
export default FormField;
Definition: More complex components composed of molecules and atoms that form distinct sections of a UI.
Best Practices:
<Header>
, <Footer>
, <ProductCard>
.Example Component Code :
// LoginForm.js (Organism)
import React, { useState } from 'react';
import FormField from './FormField'; // Molecule
import Button from './Button'; // Atom
const LoginForm = ({ onSubmit }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);
const handleEmailChange = (e) => setEmail(e.target.value);
const handlePasswordChange = (e) => setPassword(e.target.value);
const handleSubmit = (e) => {
e.preventDefault();
setIsLoading(true);
onSubmit({ email, password }).finally(() => setIsLoading(false));
};
return (
<form onSubmit={handleSubmit} className="w-full max-w-sm mx-auto">
<FormField
label="Email"
type="email"
name="email"
value={email}
onChange={handleEmailChange}
isDisabled={isLoading}
/>
<LabeledInput
label="Password"
type="password"
name="password"
value={password}
onChange={handlePasswordChange}
isDisabled={isLoading}
/>
<Button label="Login" isDisabled={!email || !password} isLoading={isLoading} />
</form>
);
};
export default LoginForm;
<LandingPageTemplate>
, <DashboardTemplate>
.// BasicTemplate.js (Template)
import React from 'react';
import Header from './Header'; // Organism
import Footer from './Footer'; // Organism
const BasicTemplate = ({children) => {
return (
<div className="min-h-screen flex flex-col bg-gray-100">
<Header />
<main className="flex-grow flex justify-center items-center">
{children}
</main>
<Footer />
</div>
);
};
export default BasicTemplate;