Hey there! Let's create a simple but good-looking React app using some modern tools. We'll make a task management app that's actually useful and looks decent. No boring stuff - let's jump right in!
Setting Up the Project
First, let's create our project. Open your terminal and run:
npm create vite@latest my-task-app -- --template react-ts
cd my-task-app
Now, let's add Tailwind CSS for styling:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Quick Configuration
Update your tailwind.config.js
:
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Add Tailwind to your src/index.css
:
@tailwind base;
@tailwind components;
@tailwind utilities;
Let's Build Something Cool
We'll create a task manager with the ability to add, complete, and delete tasks. First, let's define our task type in src/types.ts
:
export interface Task {
id: number;
text: string;
completed: boolean;
}
Now, let's create our main app in src/App.tsx
:
import { useState } from 'react'
import { Task } from './types'
function App() {
const [tasks, setTasks] = useState<Task[]>([])
const [newTask, setNewTask] = useState('')
const addTask = () => {
if (!newTask.trim()) return
setTasks([
...tasks,
{
id: Date.now(),
text: newTask,
completed: false
}
])
setNewTask('')
}
const toggleTask = (id: number) => {
setTasks(tasks.map(task =>
task.id === id ? { ...task, completed: !task.completed } : task
))
}
const deleteTask = (id: number) => {
setTasks(tasks.filter(task => task.id !== id))
}
return (
<div className="min-h-screen bg-gray-100 py-8">
<div className="max-w-md mx-auto bg-white rounded-lg shadow-md p-6">
<h1 className="text-2xl font-bold text-center mb-6">Task Manager</h1>
<div className="flex mb-4">
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
className="flex-1 p-2 border rounded-l-lg focus:outline-none focus:border-blue-500"
placeholder="Add a new task..."
/>
<button
onClick={addTask}
className="bg-blue-500 text-white px-4 rounded-r-lg hover:bg-blue-600"
>
Add
</button>
</div>
<div className="space-y-2">
{tasks.map((task) => (
<div
key={task.id}
className="flex items-center p-3 bg-gray-50 rounded-lg"
>
<label className="flex items-center flex-1 cursor-pointer">
<input
type="checkbox"
checked={task.completed}
onChange={() => toggleTask(task.id)}
className="mr-3 h-4 w-4 cursor-pointer accent-blue-500"
/>
<span
className={`flex-1 ${
task.completed ? "line-through text-gray-500" : ""
}`}
>
{task.text}
</span>
</label>
<button
onClick={() => deleteTask(task.id)}
className="text-red-500 hover:text-red-700"
>
Delete
</button>
</div>
))}
</div>
</div>
</div>
)
}
export default App
Running the App
Start the development server:
npm run dev
That's it! You now have a functional task manager with a clean, modern look. Here's what we've built:
- A responsive layout with a centered card design
- Input field with a connected add button
- Task list with completion toggling and deletion
- Clean animations and hover states
- TypeScript for type safety
- Modern styling with Tailwind CSS
Making It Even Better
Want to take it further? Here are some quick improvements you could add:
- Add local storage to persist tasks:
// Add and update to App.tsx
// Initialize state with a function that checks localStorage
const [tasks, setTasks] = useState<Task[]>(() => {
const savedTasks = localStorage.getItem('tasks')
return savedTasks ? JSON.parse(savedTasks) : []
})
const [newTask, setNewTask] = useState('')
// Only need one useEffect to handle updates
useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(tasks))
}, [tasks])
// Rest of your code remains the same
- Add keyboard support:
// Add to input element
onKeyPress={(e) => {
if (e.key === 'Enter') addTask()
}}
That's all! You now have a modern React app that's actually useful and looks good. The best part? It's built with modern tools and best practices, but keeps things simple and maintainable.
Want to experiment? Try adding categories, due dates, or priority levels to make it even more useful!
Remember: Good code doesn't have to be complicated. Keep it simple, readable, and functional! 🚀
Top comments (0)