A modern, responsive browser-based image editor built with React, TypeScript, Fabric.js, and Tailwind CSS.
The project provides a lightweight editing experience directly in the browser, allowing users to upload images, add shapes and text, apply image filters, manage objects, undo/redo changes, and export their final work as a PNG image.
π Live Demo: https://image-editor-ivory-eta.vercel.app
- Upload images from your device
- Add images using a URL
- Apply image filters
- Adjust brightness
- Adjust contrast
- Adjust saturation
- Apply blur
- Toggle additional image effects
- Reset image filters
- Change image shape using clipping paths
Add and customize different shapes directly on the canvas:
- Square
- Circle
- Triangle
- Ellipse
- Line
- Star
Shapes support customization such as:
- Fill color
- Stroke color
- Stroke width
- Opacity
- Position and transformation
- Add text
- Add text boxes
- Change font family
- Change font size
- Change font weight
- Italic text
- Text alignment
- Customize text appearance
Selected objects can be:
- Duplicated
- Deleted
- Moved forward
- Moved backward
- Brought to front
- Sent to back
- Aligned left
- Aligned center
- Aligned right
- Aligned top
- Aligned middle
- Aligned bottom
- Flipped horizontally
- Flipped vertically
- Grouped
- Ungrouped
The editor includes an undo/redo system with canvas state history.
- Undo changes
- Redo changes
- Persist canvas state in
localStorage - Restore the previous canvas after refreshing the page
Common editing actions can also be performed using keyboard shortcuts, including actions such as:
- Delete
- Undo
- Redo
- Copy
- Paste
- Duplicate
- Group
- Ungroup
- Custom canvas background color
- Clear canvas
- Responsive canvas sizing
- PNG export
- High-quality canvas rendering
The editor is designed to work across different screen sizes.
On smaller screens, the properties panel changes into a mobile-friendly bottom sheet interface to make editing easier on touch devices.
| Technology | Purpose |
|---|---|
| React | UI and component architecture |
| TypeScript | Static typing and safer development |
| Fabric.js | Canvas rendering and object manipulation |
| Tailwind CSS | Styling and responsive UI |
| Vite | Development server and build tooling |
| Lucide React | Interface icons |
| Vercel | Deployment |
| Vercel Analytics | Basic usage analytics |
| oxlint | Code linting |
The project separates UI components, editor logic, reusable hooks, and utility functions.
src/
βββ components/
β βββ CanvasEditor.tsx
β βββ Header.tsx
β βββ PropertiesPanel.tsx
β βββ Toolbar.tsx
β
βββ hooks/
β βββ useCanvasHistory.ts
β βββ useCanvasSelection.ts
β βββ useImageTools.ts
β βββ useKeyboardShortcuts.ts
β βββ useObjectActions.ts
β βββ useResponsiveCanvas.ts
β βββ useShapeTools.ts
β
βββ lib/
β βββ canvas-constants.ts
β βββ image-clip-paths.ts
β βββ image-filters.ts
β
βββ App.tsx
βββ main.tsx
βββ index.css
ββββββββββββββββββββ
β UI β
β Toolbar / Header β
β Properties Panel β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β CanvasEditor β
β Orchestration β
ββββββββββ¬ββββββββββ
β
ββββββββββββββββΌβββββββββββββββ
βΌ βΌ βΌ
βββββββββββββ βββββββββββββ βββββββββββββ
β Hooks β β Lib β β Fabric β
β β β β β JS β
βββββββββββββ βββββββββββββ βββββββββββββ
The editor logic is divided into focused hooks instead of keeping all canvas operations inside a single component.
For example:
useShapeToolshandles shape creationuseImageToolshandles image-related operationsuseObjectActionshandles object manipulationuseCanvasHistorymanages undo/redo and persistenceuseCanvasSelectionmanages the currently selected objectuseKeyboardShortcutshandles keyboard interactionsuseResponsiveCanvasmanages responsive canvas sizing
git clone https://github.com/Javadbn88/Image-Editor.gitcd Image-Editornpm installnpm run devThe application will be available at the local development URL provided by Vite.
npm run devStarts the Vite development server.
npm run buildRuns TypeScript compilation and creates a production build.
npm run lintRuns the project's linting checks.
npm run previewServes the production build locally for previewing.
The editor stores the current canvas state in the browser's localStorage.
This allows the editor to restore the previous editing session after a page refresh.
The canvas state is serialized using Fabric.js and stored as JSON.
Canvas
β
Fabric.js JSON
β
localStorage
β
Page Refresh
β
Canvas Restoration
The editor maintains a history stack of canvas states.
When an editable action is committed:
User Action
β
Canvas State
β
Serialize to JSON
β
History Stack
Undo and redo operations restore previous serialized canvas states.
A history limit is used to prevent the history stack from growing indefinitely.
Building a browser-based image editor introduces several challenges compared with a typical React application.
Fabric.js maintains its own internal canvas state, while React manages the application UI.
The project separates these responsibilities and uses React hooks to coordinate between the UI and Fabric.js.
Undo and redo require complete canvas snapshots rather than simply changing React state.
The editor therefore serializes Fabric.js canvas state and maintains a history stack.
Different Fabric.js object types require different controls.
For example:
Image
Text
Shape
Line
Group
ActiveSelection
The properties panel adapts its available controls based on the selected object's type.
The canvas has a fixed logical editing area while its displayed dimensions can adapt to the available screen size.
This allows the editor to remain usable on both desktop and mobile screens.
The main goals of the project are:
- Keep the editing experience simple
- Provide useful image-editing functionality without a backend
- Maintain a clean component architecture
- Separate canvas logic from UI logic
- Support desktop and mobile layouts
- Keep the application lightweight
- Provide a foundation for future editing features
GitHub: https://github.com/Javadbn88/Image-Editor
Live Demo: https://image-editor-ivory-eta.vercel.app
This project is currently available for personal and educational use.
If you plan to reuse or distribute the project, please check the repository for the latest licensing information.
Built by Javad
If you find the project interesting, feel free to β the repository or share your feedback.
