โ† Back to all guides
๐ŸŽจ

Build a Digital Mood Board App

Create a drag-and-drop mood board for planning aesthetics, projects, and vibes. Pinterest but make it yours.

Projectsbeginner6 min read

Build a Digital Mood Board App

Pinterest is great but sometimes you just want a blank canvas where you can throw images, colors, text, and vibes together without an algorithm telling you what to look at. Let's build your own mood board app.

๐Ÿ’ก Pro tip

Want to see the finished app first? Try the live demo and come back to learn how it works!

Why Would You Build This?

Real talk โ€” mood boards aren't just for aesthetics (although they're great for that). People use them for:

  • Planning a rebrand โ€” collecting colors, fonts, and visual inspo before redesigning a website or social media
  • Apartment decorating โ€” pulling together furniture, paint colors, and textures before you commit
  • Event planning โ€” weddings, parties, photoshoots โ€” visualizing the vibe before spending money
  • Creative projects โ€” album art, YouTube thumbnails, merch designs
  • Vision boards โ€” goals, affirmations, dream life visualization

And building it yourself means no watermarks, no subscription fees, and no ads for things you already bought.

๐Ÿ’ฌ Denise says

I use mood boards for literally everything โ€” redesigning my website, planning content, even figuring out what I want my apartment to look like. Building one as a coding project means you learn drag-and-drop, canvas layouts, and image handling, all while making something you'll genuinely use.

What We're Building

  • A blank canvas you can add items to
  • Drag and drop to rearrange
  • Add images (from URL or upload)
  • Add color swatches
  • Add text notes
  • Save your board to come back to later

Step 1: The Board Data

1// Each item on the board has a position, size, and content
2const boardItem = {
3id: 1,
4type: 'image', // 'image', 'color', 'text'
5content: 'https://example.com/photo.jpg', // URL, hex color, or text
6x: 120, // position from left
7y: 80, // position from top
8width: 200,
9height: 250,
10rotation: -3, // slight tilt for that collage feel
11};
12
13// A board is just a collection of items
14const board = {
15id: 'spring-vibes',
16name: 'Spring Vibes',
17items: [],
18background: '#FFF8F0',
19};

Step 2: Draggable Item Component

1import { useState } from 'react';
2
3function BoardItem({ item, onMove, onDelete }) {
4const [isDragging, setIsDragging] = useState(false);
5const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
6
7const handleMouseDown = (e) => {
8setIsDragging(true);
9setDragStart({
10x: e.clientX - item.x,
11y: e.clientY - item.y,
12});
13};
14
15const handleMouseMove = (e) => {
16if (!isDragging) return;
17onMove(item.id, {
18x: e.clientX - dragStart.x,
19y: e.clientY - dragStart.y,
20});
21};
22
23const handleMouseUp = () => {
24setIsDragging(false);
25};
26
27return (
28<div
29className={`board-item ${isDragging ? 'dragging' : ''}`}
30style={{
31left: item.x,
32top: item.y,
33width: item.width,
34transform: 'rotate(' + item.rotation + 'deg)',
35}}
36onMouseDown={handleMouseDown}
37onMouseMove={handleMouseMove}
38onMouseUp={handleMouseUp}
39>
40{item.type === 'image' && (
41<img src={item.content} alt='' draggable={false} />
42)}
43{item.type === 'color' && (
44<div className='color-swatch' style={{ background: item.content }} />
45)}
46{item.type === 'text' && (
47<p className='board-text'>{item.content}</p>
48)}
49
50<button className='delete-item' onClick={() => onDelete(item.id)}>x</button>
51</div>
52);
53}

Step 3: The Toolbar

1function Toolbar({ onAddItem }) {
2const [showColorPicker, setShowColorPicker] = useState(false);
3
4const addImage = () => {
5const url = prompt('Paste an image URL:');
6if (url) {
7onAddItem({
8type: 'image',
9content: url,
10width: 200,
11height: 250,
12rotation: Math.random() * 6 - 3, // random tilt between -3 and 3
13});
14}
15};
16
17const addText = () => {
18const text = prompt('What do you want to add?');
19if (text) {
20onAddItem({
21type: 'text',
22content: text,
23width: 180,
24height: 'auto',
25rotation: Math.random() * 4 - 2,
26});
27}
28};
29
30const addColor = (color) => {
31onAddItem({
32type: 'color',
33content: color,
34width: 80,
35height: 80,
36rotation: Math.random() * 8 - 4,
37});
38setShowColorPicker(false);
39};
40
41const presetColors = [
42'#F4A7BB', '#C4B8E8', '#A8D8EA', '#F0D9A0',
43'#F2A5C0', '#F5C2D0', '#FEF1C7', '#957DAD',
44'#FF6B6B', '#4ECDC4', '#2D2D2D', '#FFFFFF',
45];
46
47return (
48<div className='toolbar'>
49<button onClick={addImage}>๐Ÿ–ผ๏ธ Image</button>
50<button onClick={addText}>โœ๏ธ Text</button>
51<button onClick={() => setShowColorPicker(!showColorPicker)}>
52๐ŸŽจ Color
53</button>
54
55{showColorPicker && (
56<div className='color-grid'>
57{presetColors.map(color => (
58<button
59key={color}
60className='color-option'
61style={{ background: color }}
62onClick={() => addColor(color)}
63/>
64))}
65</div>
66)}
67</div>
68);
69}

Step 4: The Full Board

1function MoodBoard() {
2const [items, setItems] = useState([]);
3const [boardName, setBoardName] = useState('My Mood Board');
4
5const addItem = (itemData) => {
6setItems(prev => [...prev, {
7...itemData,
8id: Date.now(),
9x: 100 + Math.random() * 200,
10y: 100 + Math.random() * 200,
11}]);
12};
13
14const moveItem = (id, position) => {
15setItems(prev => prev.map(item =>
16item.id === id ? { ...item, ...position } : item
17));
18};
19
20const deleteItem = (id) => {
21setItems(prev => prev.filter(item => item.id !== id));
22};
23
24const saveBoard = () => {
25const data = { name: boardName, items };
26localStorage.setItem('moodboard', JSON.stringify(data));
27};
28
29return (
30<div className='mood-board-app'>
31<header className='board-header'>
32<input
33value={boardName}
34onChange={e => setBoardName(e.target.value)}
35className='board-name-input'
36/>
37<button onClick={saveBoard} className='save-btn'>
38Save Board
39</button>
40</header>
41
42<Toolbar onAddItem={addItem} />
43
44<div className='canvas'>
45{items.map(item => (
46<BoardItem
47key={item.id}
48item={item}
49onMove={moveItem}
50onDelete={deleteItem}
51/>
52))}
53{items.length === 0 && (
54<p className='empty-canvas'>
55Click the buttons above to start adding to your board โœจ
56</p>
57)}
58</div>
59</div>
60);
61}

Level Up Ideas

  • Multiple boards โ€” save and switch between different mood boards
  • File upload โ€” drag images from your computer instead of pasting URLs
  • Resize handles โ€” drag corners to resize items
  • Layers โ€” bring items forward or send them backward
  • Export as image โ€” save your board as a PNG to share
  • Collaborative โ€” share a board link and build together in real-time

๐Ÿ’ฌ Denise says

This project teaches you drag-and-drop interactions, dynamic positioning, state management with arrays, and localStorage โ€” all real skills that show up in professional apps. And you end up with something beautiful that you can use for your next project, room makeover, or event. Building pretty things that teach you real skills? That's the vibe.

๐Ÿ“ธ

Photo coming soon โœจ

๐Ÿš€

Want to keep going?

Tell me what you want to build next and I'll help you write the code.

Start Building โœจ