Paint Board

An interactive canvas where users can draw, express, and bring their ideas to life with every stroke.

Paint
Canvas
Create

🛠️ Tools

Brush Size5px

🎨 Colors

Current Color

Installation

Install Dependencies

npminstallfabricsonnerlucide-reactreact-icons

Add into your project

src/ToolBar.tsx
import React from "react";
import { FaBrush, FaEraser, FaUndo, FaMinus, FaPlus } from "react-icons/fa";

interface ToolBarProps {
  activeTool: "draw" | "erase";
  onToolClick: (tool: "draw" | "erase") => void;
  onClear: () => void;
  brushSize: number;
  onBrushSizeChange: (size: number) => void;
}

export const ToolBar: React.FC<ToolBarProps> = ({ 
  activeTool, 
  onToolClick, 
  onClear, 
  brushSize, 
  onBrushSizeChange 
}) => {
  return (
    <div className="bg-gray-50 rounded-xl p-4 space-y-4 border border-gray-200">
      <h3 className="font-semibold text-gray-800 text-center mb-4 -ml-6"> Tools</h3>
      
      <div className="space-y-2">
        <button
          onClick={() => onToolClick("draw")}
          className={`w-full flex items-center justify-center gap-2 h-12 px-4 rounded-lg border 
          ${activeTool === "draw" ? "bg-blue-500 text-white" : "bg-white 
          text-gray-700 border-gray-300 hover:bg-gray-100"}`}>
          <FaBrush />
          Brush
        </button>
        
        <button
          onClick={() => onToolClick("erase")}
          className={`w-full flex items-center justify-center gap-2 h-12 px-4 rounded-lg border 
          ${activeTool === "erase" ? "bg-blue-500 text-white" : "bg-white text-gray-700
          border-gray-300 hover:bg-gray-100"}`}>
          <FaEraser />
          Eraser
        </button>
      </div>

      <div className="space-y-3">
        <div className="flex items-center justify-between">
          <span className="text-sm font-medium text-gray-700">Brush Size</span>
          <span className="text-sm text-gray-500">{brushSize}px</span>
        </div>
        
        <div className="flex items-center gap-2">
          <button
            onClick={() => onBrushSizeChange(Math.max(1, brushSize - 1))}
            disabled={brushSize <= 1}
            className="p-2 rounded-lg border bg-gray-200 hover:bg-gray-300 
            disabled:opacity-50">
            <FaMinus />
          </button>

          <input
            type="range"
            value={brushSize}
            onChange={(e) => onBrushSizeChange(parseInt(e.target.value))}
            min={1}
            max={20}
            step={1}
            className="flex-1"/>

          <button
            onClick={() => onBrushSizeChange(Math.min(20, brushSize + 1))}
            disabled={brushSize >= 20}
            className="p-2 rounded-lg border bg-gray-200 hover:bg-gray-3 disabled:opacity-50">
            <FaPlus />
          </button>
        </div>
      </div>

      <button
        onClick={onClear}
        className="w-full flex items-center justify-center gap-3 h-12 px-2
        rounded-lg bg-red-500 text-white hover:bg-red-600">
        <FaUndo />
        Clear Canvas
      </button>
    </div>
  );
};
src/ColorPicker.tsx
import { useState } from "react";

interface ColorPickerProps {
  color: string;
  onChange: (color: string) => void;
}

export const ColorPicker: React.FC<ColorPickerProps> = ({ color, onChange }) => {
  const [customColor, setCustomColor] = useState<string>(color);

  const predefinedColors: string[] = [
    "#000000",
    "#FF0000",
    "#00FF00",
    "#0000FF",
    "#FFFF00",
    "#FF00FF",
    "#00FFFF",
    "#FFA500",
    "#800080",
    "#FFC0CB",
    "#A52A2A",
    "#808080",
    "#FFE4E1",
    "#98FB98",
    "#87CEEB",
    "#DDA0DD",
  ];

  const handleColorClick = (selectedColor: string) => {
    onChange(selectedColor);
    setCustomColor(selectedColor);
  };

  const handleCustomColorChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newColor = e.target.value;
    setCustomColor(newColor);
    onChange(newColor);
  };

  return (
    <div className="bg-gray-50 rounded-xl p-4 border 
    border-gray-200 sm:p-3 sm:rounded-lg sm:max-w-xs sm:mx-auto">
      <h3 className="font-semibold text-gray-800 text-center mb-4 sm:text-base -ml-6"> Colors</h3>
      <div className="mb-4 text-center">
        <div 
          className="w-12 h-12 rounded-full border-4 border-white shadow-lg mx-auto mb-2"
          style={{ backgroundColor: color }}/>
        <span className="text-sm text-gray-600">Current Color</span>
      </div>
      <div className="grid grid-cols-4 gap-2 mb-4 sm:gap-1 justify-items-center">
        {predefinedColors.map((predefinedColor) => (
          <button
            key={predefinedColor}
            onClick={() => handleColorClick(predefinedColor)}
            className={`w-12 h-12 sm:w-9 sm:h-9 rounded-lg border-2 transition-all hover:scale-110 
            ${color === predefinedColor ? "border-gray-800 shadow-lg" : "border-gray-300 
            hover:border-gray-500"}`}
            style={{ backgroundColor: predefinedColor }}/>
        ))}
      </div>
      <div className="space-y-2">
        <label className="text-sm font-medium text-gray-700 ml-2">Custom Color</label>
        <div className="flex justify-evenly gap-2 mt-1">
          <input
            type="color"
            value={customColor}
            onChange={handleCustomColorChange}
            className="w-12 h-10 rounded-md border border-gray-300 p-1"/>
          <input
            type="text"
            value={customColor}
            onChange={handleCustomColorChange}
            placeholder="#FFFFFF"
            className="h-10 text-sm border border-gray-300 rounded-md px-2 w-[120px]"/>
        </div>
      </div>
    </div>
  );
};

Update App file

App.jsx

<PaintBoard/>