Setup and context — Why Build a Note-Taking App?
Note-taking apps are among the most universally used mobile applications. From Apple Notes to Google Keep, millions of people rely on them daily to capture ideas, organize tasks, and stay productive.
Below, you'll build a complete note-taking app using Rork. With Rork's AI-powered code generation, even beginners can put together a polished, functional notes app in a fraction of the usual time.
What you'll learn:
- How to design the screen structure for a notes app in Rork
- Data persistence using AsyncStorage (save and load notes locally)
- Real-time search across note titles and content
- Category tagging and filtering
- Tips for achieving a professional-quality design
Who this is for: Anyone getting started with Rork, or anyone who wants to learn by building a practical, everyday app.
Prerequisites and Setup
What You'll Need
Before diving in, make sure you have:
- A Rork account: Sign up for free at rork.com (the Free plan allows up to 5 project generations per week)
- A modern browser: Chrome or Safari, latest version
- A smartphone: For live preview on a real device (iOS or Android)
Rork Basics
If this is your first time using Rork, start with the Getting Started guide to familiarize yourself with project creation and the preview workflow.
Step 1 — Creating Your Project with the Right Prompt
The most critical part of building an app with Rork is crafting your initial prompt. A well-structured prompt helps the AI generate a polished app on the first try.
Recommended Prompt
Enter the following in Rork's project creation screen:
Build a note-taking app with the following specifications:
[Screens]
1. Notes List (Home): Display note titles with timestamps in a scrollable list
2. Note Editor: A form with title and body text fields
3. Search: Keyword search across all notes
[Features]
- Create, edit, and delete notes (swipe-to-delete support)
- Local persistence using AsyncStorage
- Real-time search across titles and content
- Category tags: Work, Personal, Ideas, Shopping
- Category-based filtering
- Automatic timestamps with sort-by-date
[Design]
- Clean, minimal UI
- Light and dark mode support
- Color-coded category badgesThe key here is separating your instructions into screens, features, and design. Rork's AI uses this structure to generate appropriate components, navigation, and styling automatically.
Step 2 — Data Model and Storage Design
At the heart of any notes app is its data model. Here's what Rork generates for the note structure:
// types/Note.ts — Note data type definition
export interface Note {
id: string; // Unique ID (UUID)
title: string; // Note title
content: string; // Note body
category: Category; // Category tag
createdAt: string; // Created timestamp (ISO 8601)
updatedAt: string; // Last updated timestamp
}
// Category definitions
export type Category = 'work' | 'personal' | 'idea' | 'shopping';
// Display labels and colors for each category
export const CATEGORIES: Record<Category, { label: string; color: string }> = {
work: { label: 'Work', color: '#4A90D9' },
personal: { label: 'Personal', color: '#7ED321' },
idea: { label: 'Ideas', color: '#F5A623' },
shopping: { label: 'Shopping', color: '#D0021B' },
};Persisting Data with AsyncStorage
AsyncStorage ensures your notes survive app restarts. Here's the storage utility Rork generates:
// utils/storage.ts — Save, load, and delete notes
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Note } from '../types/Note';
const STORAGE_KEY = '@notes_app_data';
// Load all notes
export const loadNotes = async (): Promise<Note[]> => {
try {
const json = await AsyncStorage.getItem(STORAGE_KEY);
return json ? JSON.parse(json) : [];
} catch (error) {
console.error('Failed to load notes:', error);
return [];
}
};
// Save notes (overwrites entire array)
export const saveNotes = async (notes: Note[]): Promise<void> => {
try {
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(notes));
} catch (error) {
console.error('Failed to save notes:', error);
}
};
// Expected behavior:
// - loadNotes() → Returns saved notes array (empty array on first run)
// - saveNotes([...]) → Persists the notes array to device storageAsyncStorage is a key-value store that saves data as JSON strings. It works well for personal note-taking apps. For apps handling tens of thousands of records, consider migrating to SQLite, but AsyncStorage is more than sufficient for most use cases.
For a deeper dive into offline data strategies, check out Building Offline-Ready Apps with AsyncStorage and NetInfo.
Step 3 — Building the Notes List Screen
The notes list is the first screen users see, so readability and ease of interaction are paramount.
// screens/NoteListScreen.tsx — Core notes list implementation
import React, { useState, useEffect, useCallback } from 'react';
import { FlatList, View, Text, TouchableOpacity, Alert } from 'react-native';
import { loadNotes, saveNotes } from '../utils/storage';
import { Note, CATEGORIES } from '../types/Note';
export default function NoteListScreen({ navigation }) {
const [notes, setNotes] = useState<Note[]>([]);
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
// Load notes whenever the screen comes into focus
useEffect(() => {
const unsubscribe = navigation.addListener('focus', async () => {
const saved = await loadNotes();
// Sort by most recently updated
setNotes(saved.sort((a, b) =>
new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
));
});
return unsubscribe;
}, [navigation]);
// Delete a note with confirmation
const deleteNote = useCallback(async (id: string) => {
Alert.alert('Delete Note', 'Are you sure you want to delete this note?', [
{ text: 'Cancel', style: 'cancel' },
{
text: 'Delete',
style: 'destructive',
onPress: async () => {
const updated = notes.filter(n => n.id !== id);
setNotes(updated);
await saveNotes(updated);
},
},
]);
}, [notes]);
// Apply category filter
const filteredNotes = selectedCategory
? notes.filter(n => n.category === selectedCategory)
: notes;
return (
<View style={{ flex: 1, padding: 16 }}>
{/* Category filter buttons */}
<CategoryFilter
selected={selectedCategory}
onSelect={setSelectedCategory}
/>
{/* Notes list */}
<FlatList
data={filteredNotes}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<NoteCard
note={item}
onPress={() => navigation.navigate('Edit', { noteId: item.id })}
onDelete={() => deleteNote(item.id)}
/>
)}
ListEmptyComponent={
<Text style={{ textAlign: 'center', marginTop: 40, color: '#999' }}>
No notes yet. Tap the + button to create one!
</Text>
}
/>
</View>
);
}Why FlatList Matters
React Native's FlatList only renders items currently visible on screen. This means your app stays smooth and responsive even if you have hundreds or thousands of notes — it won't try to render them all at once.
Step 4 — Adding Real-Time Search
As your note collection grows, search becomes essential. Here's how to implement keyword-based filtering:
// hooks/useNoteSearch.ts — Custom hook for note search
import { useMemo } from 'react';
import { Note } from '../types/Note';
export function useNoteSearch(notes: Note[], query: string): Note[] {
return useMemo(() => {
if (!query.trim()) return notes;
const lowerQuery = query.toLowerCase();
return notes.filter(note =>
note.title.toLowerCase().includes(lowerQuery) ||
note.content.toLowerCase().includes(lowerQuery)
);
}, [notes, query]);
// Expected behavior:
// useNoteSearch(allNotes, '') → Returns all notes
// useNoteSearch(allNotes, 'meeting') → Returns only notes containing "meeting"
}The useMemo hook ensures filtering only runs when the notes array or search query actually changes, keeping the UI responsive during rapid typing.
Adding Search via Rork Chat
If you didn't include search in your initial prompt, you can easily add it through Rork's chat interface:
Add a search bar at the top of the notes list screen.
It should search across both titles and content in real time.
Show a "X results found" label below the search bar while filtering.Step 5 — Polishing the Design
A few small design touches can transform your note-taking app from functional to professional.
Color-Coded Category Badges
Adding visual category badges to each note card dramatically improves scannability:
// components/CategoryBadge.tsx — Category badge component
import React from 'react';
import { View, Text } from 'react-native';
import { Category, CATEGORIES } from '../types/Note';
export function CategoryBadge({ category }: { category: Category }) {
const { label, color } = CATEGORIES[category];
return (
<View style={{
backgroundColor: color + '20', // 20% opacity background
paddingHorizontal: 8,
paddingVertical: 3,
borderRadius: 12,
alignSelf: 'flex-start',
}}>
<Text style={{ color, fontSize: 12, fontWeight: '600' }}>
{label}
</Text>
</View>
);
}Dark Mode Support
When you include "dark mode" in your Rork prompt, the AI generates automatic theme switching using React Native's useColorScheme hook. For further customization, use the chat to specify exact colors — for example, "Set the dark mode background to #1A1A2E" — and Rork will update the theme accordingly.
Wrapping Up — Start Your App Journey with a Notes App
A note-taking app is the perfect first project. It's simple enough for beginners yet covers fundamental patterns that appear in almost every mobile app:
- Data modeling — Defining type-safe structures with TypeScript
- Data persistence — Keeping data alive between sessions with AsyncStorage
- Efficient list rendering — Using FlatList for smooth scrolling at scale
- Real-time search — Optimized filtering with useMemo
- Category management — Organized, filterable content with visual cues
From here, you could extend the app with Markdown support, reminders, cloud sync, or rich text editing — all features that could make your app ready for the App Store. Fire up Rork, paste in the prompt, and start building your own notes app today.
As a next step, try Build Your First Rork App in 30 Minutes to get more comfortable with the workflow, or How to Build a To-Do App to learn task management patterns.