A simple task manager demonstrating Firestate's key features in a React application.
- Document subscription - Task list name syncs in real-time
- Collection subscription - Tasks are automatically synced
- Undo/Redo - Full undo/redo support with keyboard shortcuts
- Sync indicators - Visual feedback for save status
- CRUD operations - Add, update, and delete tasks
- Optimistic updates - Changes appear immediately
- Go to the Firebase Console
- Create a new project (or use an existing one)
- Enable Cloud Firestore:
- Navigate to Build > Firestore Database
- Click "Create database"
- Start in test mode for development
- In Firebase Console, go to Project Settings (gear icon)
- Scroll down to "Your apps"
- Click "Add app" and select Web (</>)
- Register your app and copy the config object
Edit src/firebase.ts and replace the placeholder config with your values:
const firebaseConfig = {
apiKey: 'YOUR_API_KEY',
authDomain: 'your-project.firebaseapp.com',
projectId: 'your-project',
storageBucket: 'your-project.appspot.com',
messagingSenderId: '123456789',
appId: '1:123456789:web:abcdef123456',
}# Install dependencies
pnpm install
# Start development server
pnpm devThe app will be available at http://localhost:5173.
- Create a task list - Click the button to create your first task list
- Edit the title - Click on the list name to edit it
- Add tasks - Type in the input and press Enter or click Add
- Toggle completion - Click the checkbox
- Change priority - Use the dropdown to set Low/Medium/High
- Delete tasks - Click the Delete button
- Undo/Redo - Use the buttons or
Ctrl/Cmd+ZandCtrl/Cmd+Y
Open the app in multiple browser tabs to see real-time synchronization in action. Changes made in one tab will appear instantly in others.
src/
├── firebase.ts # Firebase initialization
├── schemas.ts # Firestate schema definitions
├── App.tsx # Main React component
└── main.tsx # React entry point
// Define your data shape with Zod
const TaskSchema = z.object({
title: z.string(),
completed: z.boolean(),
priority: z.enum(['low', 'medium', 'high']),
createdAt: z.number(),
})
// Create a collection definition
const tasksCollection = defineCollection({
schema: TaskSchema,
path: (params) => `taskLists/${params.listId}/tasks`,
autosave: 500,
})// Subscribe to the collection
const tasks = useCollection({ definition: tasksCollection, params })
// Update a task
tasks.update({ [taskId]: { completed: true } })
// Add a new task
tasks.add('new-id', { title: 'New Task', completed: false, ... })
// Remove a task
tasks.remove(taskId)const { undo, redo, canUndo, canRedo } = useUndoManager()
// Enable keyboard shortcuts
useUndoKeyboardShortcuts()