Color Generator - React, Vite, JavaScript, Values.js, React-Toastify, Clipboard API, Fundamental Project 9
A hands-on React app that generates color palettes from any hex color. Enter a hex code or use the built-in color picker to get a full set of tints and shades, then copy any hex value to the clipboard with one click. Built with React, Vite, values.js, and react-toastify—ideal for learning component state, third-party libraries, and the Clipboard API.
- Live Demo: https://create-color.vercel.app/
- Project Summary
- Live Demo
- Features
- Technologies Used
- Project Structure
- Setup & Installation
- Environment Variables (.env)
- How to Run & Use
- Usage Instructions
- Component Walkthrough
- Key Functionality & APIs
- Routes & Architecture
- Styling and Responsive Design
- Code Examples & Teaching Content
- Reusing Components in Other Projects
- Learning Outcomes
- Keywords
- Conclusion
- License
This project is a client-side only color palette generator. There is no backend server or database: all logic runs in the browser. You pick or type a hex color, and the app uses the values.js library to compute tints (lighter) and shades (darker) in 10% steps. Each swatch is clickable to copy its hex code via the Clipboard API, with react-toastify used for success and error messages. The UI is built with React functional components and hooks, styled with CSS (including CSS Grid), and bundled with Vite.
Production URL: https://create-color.vercel.app/
You can use the live demo without installing anything—enter a hex (e.g. #f15025) or use the color picker, then click any generated color to copy its hex value.
- Hex input & color picker — Enter a color as hex (e.g.
#f15025) or use the native color picker. - Instant palette generation — Generate a full set of tints and shades (10% steps) from one base color.
- Copy to clipboard — Click any color swatch to copy its hex code; toast confirms success or error.
- Responsive grid — Color grid uses CSS Grid and adapts to different screen sizes.
- Toast notifications — Success and error feedback via react-toastify (e.g. invalid hex, copy success/failure).
- Component-based structure — Clear separation:
App(state),Form(input),ColorList/SingleColor(display and copy).
| Technology | Purpose |
|---|---|
| React 18 | UI components, state (useState), composition |
| Vite 4 | Build tool, dev server, HMR |
| JavaScript (ES6+) | No TypeScript; modern JS and JSX |
| values.js | Generate tints/shades from a hex color |
| react-toastify | Toast notifications (success/error) |
| nanoid | Unique keys for list items |
| Clipboard API | Browser API to copy hex to clipboard |
| CSS Grid | Responsive layout for color swatches |
09-color-generator/
├── public/
│ └── vite.svg # Favicon / app icon
├── src/
│ ├── components/
│ │ ├── Form.jsx # Color input form (hex + color picker)
│ │ ├── ColorList.jsx # Grid container for color swatches
│ │ └── SingleColor.jsx # One swatch + copy-on-click
│ ├── App.jsx # Root: state, addColor, Form + ColorList
│ ├── main.jsx # React root mount + global CSS imports
│ └── index.css # Global + project-specific styles
├── index.html # Entry HTML, meta, script to main.jsx
├── vite.config.js # Vite + React plugin config
├── package.json
├── eslint.config.js # ESLint 9 flat config (React, hooks)
└── README.mdEntry point: index.html loads /src/main.jsx → main.jsx renders <App /> into #root. There are no route definitions (single-page app, single view).
-
Clone the repository
git clone https://github.com/arnobt78/Color-Generator--React-Fundamental-Project-9.git cd Color-Generator--React-Fundamental-Project-9 -
Install dependencies
npm install
-
Start the development server
npm run dev
The app will be at
http://localhost:5173(or the port Vite prints in the terminal). -
Build for production
npm run build
Output goes to
dist/. Preview the production build with:npm run preview
-
Lint
npm run lint
Runs ESLint on
src/with zero warnings allowed.
This project does not use any environment variables out of the box. All behavior is driven by user input and client-side libraries (values.js, react-toastify). There are no API keys, feature flags, or backend URLs to configure.
If you extend the project (e.g. analytics, optional API, or feature flags), you can use Vite’s env support:
-
Creating env files: In the project root, add
.env,.env.local,.env.development, or.env.production. -
Naming: Only variables prefixed with
VITE_are exposed to the client. Example:VITE_APP_TITLE=Color Generator. -
Usage in code: Read them via
import.meta.env.VITE_APP_TITLE. Do not put secrets inVITE_*—they are embedded in the client bundle. -
Example:
Create.env.localwith:VITE_APP_TITLE=Color Generator
Then in JS:
const title = import.meta.env.VITE_APP_TITLE;
No .env file is required to run or build the project as-is.
- Development:
npm run dev→ open the URL shown (e.g.http://localhost:5173). - Production build:
npm run build→npm run previewto test thedist/build locally. - Usage flow: Type or pick a color → click submit → click any swatch to copy its hex. Invalid hex shows an error toast.
- Enter a color in hex format (e.g.
#f15025) in the text input, or use the color picker. - Click submit to generate a palette of tints and shades (10% steps).
- Click any color in the grid to copy its hex code to the clipboard; a toast confirms success.
- If the input is invalid, a toast shows the error message from values.js.
- Use the copied hex codes in your design tools, CSS, or other apps.
- Role: Root component. Holds the list of generated colors and the handler that generates a new palette from a hex string.
- State:
colors— array of color objects from values.js (each hashex,weight, etc.). - Handler:
addColor(color)— callsnew Values(color).all(10), updatescolors, or shows a toast on error. - Renders:
<Form addColor={addColor} />,<ColorList colors={colors} />, and<ToastContainer position='top-center' />.
- Role: Collects the user’s color input (text + color picker) and submits it to the parent.
- State:
color— current hex string (or empty). - Behavior: Both the color picker and the text input update
color; form submit callsaddColor(color). - Renders: A section with heading “color generator”, a form with color input, text input (placeholder
#f15025), and a submit button styled with the current color.
- Role: Renders the list of generated colors as a grid.
- Props:
colors— array of color objects from values.js. - Behavior: Maps over
colorsand renders aSingleColorfor each, usingnanoid()for the Reactkey. - Renders: A
<section className='colors'>containing multipleSingleColorcomponents.
- Role: One color swatch: shows weight (%) and hex, and copies hex to clipboard on click.
- Props:
index(number),color(object withhex,weight). - Behavior: Click handler checks
navigator.clipboard, thennavigator.clipboard.writeText(\#${hex}`)`, and shows success or error toast. - Renders: An
<article>with background#${hex}, weight and hex text; uses classcolor-lightwhenindex > 10for readable text on light tints.
-
Library: values.js — creates tints and shades from a single hex.
-
Usage:
import Values from "values.js"; const colors = new Values("#f15025").all(10); // 10% steps // colors is an array of objects: { hex, weight, type, ... }
-
Error handling: Invalid hex (e.g.
"red"or"#ggg") throws; the app catches and showserror.messagevia toast.
-
Setup in App.jsx:
import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; // In JSX: <ToastContainer position="top-center" />;
-
Usage:
toast.success("Color copied to clipboard"); toast.error("Invalid color value"); toast.error(error.message); // from catch block
-
API:
navigator.clipboard.writeText(text)(async, returns a Promise). -
Usage in SingleColor.jsx:
if (navigator.clipboard) { try { await navigator.clipboard.writeText(`#${hex}`); toast.success("Color copied to clipboard"); } catch { toast.error("Failed to copy color to clipboard"); } } else { toast.error("Clipboard access not available"); }
-
Note: Clipboard API requires a secure context (HTTPS or localhost).
- Routes: None. This is a single-page app with one screen: form at the top, color grid below.
- Data flow: One-way. User input →
Form→addColorinApp→colorsstate →ColorList→SingleColor. No router, no backend, no API endpoints. - Backend: There is no backend; everything runs in the browser.
-
Global styles:
src/index.css— resets, CSS variables (e.g.--primary-500,--grey-*,--borderRadius), typography, buttons, form and alert classes. -
Project-specific:
.container(form layout),.color-form,.colors(grid),.color/.color-light(swatch and text contrast). -
Grid layout:
.colors { min-height: calc(100vh - 160px); display: grid; grid-template-columns: repeat(auto-fit, minmax(223.33px, 1fr)); grid-template-rows: repeat(auto-fit, minmax(96px, 1fr)); }
-
Responsive: At
min-width: 768px, the form switches to a horizontal layout (color picker + text input + button in one row). The color grid always usesauto-fitand min widths so it adapts to screen size.
import Values from "values.js";
import { useState } from "react";
import { toast } from "react-toastify";
const [colors, setColors] = useState(new Values("#f15025").all(10));
const addColor = (color) => {
try {
const newColors = new Values(color).all(10);
setColors(newColors);
} catch (error) {
toast.error(error.message);
}
};const [color, setColor] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
addColor(color);
};
// In JSX: value={color}, onChange={(e) => setColor(e.target.value)} on both inputsconst saveToClipboard = async () => {
if (navigator.clipboard) {
try {
await navigator.clipboard.writeText(`#${hex}`);
toast.success("Color copied to clipboard");
} catch {
toast.error("Failed to copy color to clipboard");
}
} else {
toast.error("Clipboard access not available");
}
};
// On the article: onClick={saveToClipboard}import { nanoid } from "nanoid";
{
colors.map((color, index) => (
<SingleColor key={nanoid()} color={color} index={index} />
));
olors.map((color, index) => (
<SingleColor key={nanoid()} color={color} index={index} />
));
}Using nanoid() gives a unique key per item. For a static list that never reorders, index could be used as key instead.
- Form.jsx: Copy the file; it only needs
addColor(color)from the parent. You can rename the heading or placeholder and restyle with your own CSS. - ColorList.jsx: Pass any array of objects that have at least the shape
{ hex, weight }(or adapt SingleColor to your shape). Replacenanoidwith another key strategy if needed. - SingleColor.jsx: Reusable wherever you have a
{ hex, weight }(or similar) object. Ensure the parent app hasToastContainerandreact-toastifyCSS if you use toasts. - Pattern: State lives in a parent; Form and ColorList are presentational plus minimal behavior (submit, click-to-copy). You can wrap this in a route or embed the grid in a larger design tool UI.
- Use React functional components and
useStatefor local and lifted state. - Compose components and pass props/callbacks (Form → App → ColorList → SingleColor).
- Integrate third-party libraries (values.js, react-toastify) in a Vite + React app.
- Use the Clipboard API for copy-to-clipboard and handle success/error with toasts.
- Structure a small app with clear separation: one smart component (App) and presentational components (Form, ColorList, SingleColor).
- Apply responsive CSS Grid and CSS variables for layout and theming.
React, Color Generator, Hex Color, Tints and Shades, Color Palette, values.js, react-toastify, Color Picker, Copy to Clipboard, Clipboard API, CSS Grid, Functional Components, useState, JavaScript ES6+, Vite, Web Development, Frontend, UI, Hooks, Toast Notifications, Responsive Design.
This project is a focused introduction to React fundamentals: state, props, event handlers, and integration with external libraries and browser APIs. It has no backend or environment variables, so you can run it immediately after npm install and npm run dev. You can extend it with features like saving palettes, exporting to JSON/CSS, or switching to a different step size for tints and shades. The component structure and patterns (controlled inputs, lifted state, copy-to-clipboard) are reusable in other React apps.
This project is licensed under the MIT License. Feel free to use, modify, and distribute the code as per the terms of the license.
This is an open-source project — feel free to use, enhance, and extend this project further!
If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://www.arnobmahmud.com.
Enjoy building and learning! 🚀
Thank you! 😊
