RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Getting Started
Getting Started/2026-03-24Beginner

Build a Calendar & Schedule App with Rork — A Complete Beginner's Tutorial

Learn how to build a fully functional calendar and schedule management app from scratch using Rork. This step-by-step tutorial covers calendar UI, event CRUD, local storage, and reminder notifications.

Rork515Calendar AppSchedule ManagementTutorial5Beginner7React Native209Expo149

Setup and context — Learn by Building a Calendar App

Schedule management apps are among the most universally useful types of mobile applications. By building one, you'll naturally learn key app development concepts like state management, data persistence, UI component design, and user interaction patterns — all in a single project.

Below, we build a calendar and schedule management app from scratch using Rork. Even with minimal coding experience, you can lean on Rork's AI assistant to turn well-crafted prompts into production-ready code, freeing you to focus on design and functionality decisions.

What you'll learn:

  • Building a month-view calendar UI with event markers
  • Managing event data (create, read, update, delete)
  • Persisting data locally with AsyncStorage
  • Adding reminder notifications with Expo Notifications
  • Polishing the UI to App Store / Google Play standards

If you're brand new to Rork, we recommend starting with "Getting Started with Rork" to get familiar with the basics.


Prerequisites & Setup

What You'll Need

  • A Rork account (the free plan covers everything in this tutorial)
  • A smartphone (iOS or Android — for previewing with Expo Go)
  • A web browser on your computer (to access the Rork editor)

Helpful Background Knowledge

  • Basic understanding of HTML/CSS
  • Familiarity with JavaScript variables, functions, and arrays

That said, Rork's AI handles the heavy lifting, so you can follow along even without deep programming knowledge. Whenever something is unclear, just ask Rork's chat — it'll explain any code it generates.


Step 1: Create Your Project

Log into the Rork dashboard and click "New Project." Name it something descriptive like my-calendar-app.

For your initial prompt, try something like this:

Build a calendar and schedule management app with these features:
1. Month-view calendar UI (highlight today's date)
2. Tap a date to see that day's events
3. Event creation form (title, start time, end time, notes)
4. Edit and delete events
5. Save data locally with AsyncStorage
6. Modern, clean design with a blue color theme

Rork will generate the screen layout, components, and navigation structure based on this prompt. After a few minutes, you'll see a preview — scan the QR code with Expo Go to test it on your device.


Step 2: Build the Calendar UI

Rork typically generates calendar components using the react-native-calendars library. Here's what the core calendar component looks like with event dot markers:

// CalendarScreen.tsx — Main calendar screen
import React, { useState, useMemo } from 'react';
import { View, StyleSheet } from 'react-native';
import { Calendar } from 'react-native-calendars';
 
type Event = {
  id: string;
  title: string;
  date: string; // 'YYYY-MM-DD'
  startTime: string;
  endTime: string;
  memo: string;
};
 
type Props = {
  events: Event[];
  onDayPress: (dateString: string) => void;
};
 
export default function CalendarScreen({ events, onDayPress }: Props) {
  const [selectedDate, setSelectedDate] = useState('');
 
  // Add dot markers to dates that have events
  const markedDates = useMemo(() => {
    const marks: Record<string, any> = {};
    events.forEach((event) => {
      marks[event.date] = {
        ...marks[event.date],
        marked: true,
        dotColor: '#4A90D9',
      };
    });
    if (selectedDate) {
      marks[selectedDate] = {
        ...marks[selectedDate],
        selected: true,
        selectedColor: '#4A90D9',
      };
    }
    return marks;
  }, [events, selectedDate]);
 
  const handleDayPress = (day: { dateString: string }) => {
    setSelectedDate(day.dateString);
    onDayPress(day.dateString);
  };
 
  return (
    <View style={styles.container}>
      <Calendar
        markedDates={markedDates}
        onDayPress={handleDayPress}
        theme={{
          todayTextColor: '#4A90D9',
          arrowColor: '#4A90D9',
          monthTextColor: '#333',
          textDayFontSize: 16,
          textMonthFontSize: 18,
          textDayHeaderFontSize: 14,
        }}
      />
    </View>
  );
}
 
// Expected output:
// A month-view calendar is displayed with blue dots on dates that have events.
// Tapping a date highlights it (blue background) and shows that day's events below.
 
const styles = StyleSheet.create({
  container: {
    backgroundColor: '#FFFFFF',
    borderRadius: 12,
    overflow: 'hidden',
    margin: 16,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
});

The key detail here is using useMemo to efficiently compute markedDates. Whenever the event data changes, the calendar markers update automatically without unnecessary re-renders.


Step 3: Build the Event Creation Form

Next, let's implement the form for adding events. Give Rork a prompt like this:

Create an event form with:
- Title (required, text input)
- Date (selected via DateTimePicker)
- Start time and end time (TimePicker)
- Notes (optional, multiline text)
- Save and Cancel buttons
- Validation: show error if title is empty

Here's what the core form component typically looks like:

// AddEventForm.tsx — Event creation form (core logic)
import React, { useState } from 'react';
import {
  View, Text, TextInput, TouchableOpacity,
  Alert, StyleSheet, ScrollView,
} from 'react-native';
 
type EventInput = {
  title: string;
  date: string;
  startTime: string;
  endTime: string;
  memo: string;
};
 
type Props = {
  initialDate: string;
  onSave: (event: EventInput) => void;
  onCancel: () => void;
};
 
export default function AddEventForm({ initialDate, onSave, onCancel }: Props) {
  const [title, setTitle] = useState('');
  const [memo, setMemo] = useState('');
  const [startTime, setStartTime] = useState('09:00');
  const [endTime, setEndTime] = useState('10:00');
 
  const handleSave = () => {
    if (!title.trim()) {
      Alert.alert('Validation Error', 'Please enter a title for this event');
      return;
    }
    onSave({
      title: title.trim(),
      date: initialDate,
      startTime,
      endTime,
      memo: memo.trim(),
    });
  };
 
  return (
    <ScrollView style={styles.container}>
      <Text style={styles.label}>Title *</Text>
      <TextInput
        style={styles.input}
        value={title}
        onChangeText={setTitle}
        placeholder="Meeting, lunch, study group..."
      />
 
      <Text style={styles.label}>Start Time</Text>
      <TextInput
        style={styles.input}
        value={startTime}
        onChangeText={setStartTime}
        placeholder="09:00"
      />
 
      <Text style={styles.label}>End Time</Text>
      <TextInput
        style={styles.input}
        value={endTime}
        onChangeText={setEndTime}
        placeholder="10:00"
      />
 
      <Text style={styles.label}>Notes</Text>
      <TextInput
        style={[styles.input, styles.memoInput]}
        value={memo}
        onChangeText={setMemo}
        placeholder="Additional details (optional)"
        multiline
        numberOfLines={4}
      />
 
      <View style={styles.buttonRow}>
        <TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
          <Text style={styles.cancelText}>Cancel</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.saveButton} onPress={handleSave}>
          <Text style={styles.saveText}>Save</Text>
        </TouchableOpacity>
      </View>
    </ScrollView>
  );
}
 
// Expected output:
// A clean form with fields for title, times, and notes.
// Tapping "Save" validates the input and saves the event.
// If the title is empty, an alert reads "Please enter a title for this event."
 
const styles = StyleSheet.create({
  container: { padding: 20 },
  label: { fontSize: 14, fontWeight: '600', color: '#555', marginTop: 16, marginBottom: 6 },
  input: {
    borderWidth: 1, borderColor: '#DDD', borderRadius: 8,
    padding: 12, fontSize: 16, backgroundColor: '#FAFAFA',
  },
  memoInput: { height: 100, textAlignVertical: 'top' },
  buttonRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 24 },
  cancelButton: {
    flex: 1, marginRight: 8, padding: 14, borderRadius: 8,
    borderWidth: 1, borderColor: '#DDD', alignItems: 'center',
  },
  cancelText: { fontSize: 16, color: '#666' },
  saveButton: {
    flex: 1, marginLeft: 8, padding: 14, borderRadius: 8,
    backgroundColor: '#4A90D9', alignItems: 'center',
  },
  saveText: { fontSize: 16, color: '#FFF', fontWeight: '600' },
});

Step 4: Persist Data with AsyncStorage

To make sure events survive app restarts, we'll use AsyncStorage for local persistence.

// storage.ts — Data persistence utilities
import AsyncStorage from '@react-native-async-storage/async-storage';
 
const EVENTS_KEY = '@calendar_events';
 
export type CalendarEvent = {
  id: string;
  title: string;
  date: string;
  startTime: string;
  endTime: string;
  memo: string;
};
 
// Load all events
export async function loadEvents(): Promise<CalendarEvent[]> {
  try {
    const json = await AsyncStorage.getItem(EVENTS_KEY);
    return json ? JSON.parse(json) : [];
  } catch (error) {
    console.error('Failed to load events:', error);
    return [];
  }
}
 
// Save all events
export async function saveEvents(events: CalendarEvent[]): Promise<void> {
  try {
    await AsyncStorage.setItem(EVENTS_KEY, JSON.stringify(events));
  } catch (error) {
    console.error('Failed to save events:', error);
  }
}
 
// Add a single event
export async function addEvent(
  event: Omit<CalendarEvent, 'id'>
): Promise<CalendarEvent> {
  const events = await loadEvents();
  const newEvent: CalendarEvent = {
    ...event,
    id: Date.now().toString(),
  };
  events.push(newEvent);
  await saveEvents(events);
  return newEvent;
}
 
// Delete an event
export async function deleteEvent(id: string): Promise<void> {
  const events = await loadEvents();
  const filtered = events.filter((e) => e.id !== id);
  await saveEvents(filtered);
}
 
// Expected output:
// loadEvents() → Returns the saved events array (empty array on first call)
// addEvent({...}) → Assigns a new ID, saves, and returns the created event
// deleteEvent('123') → Removes the event with that ID and saves the updated list

This pattern gives you a solid local storage foundation. When you're ready to scale up, you can swap AsyncStorage for Supabase or Firebase to enable cloud syncing across devices.


Step 5: Add Reminder Notifications

Let your users receive a reminder before their events by adding local push notifications. Tell Rork:

Add a feature that sends a local notification reminder 15 minutes before each event.
Use Expo Notifications and schedule it automatically when an event is saved.

For a deeper dive into push notifications, check out "Implementing Push Notifications in Rork."


Common Errors and Fixes

Calendar Doesn't Render

This usually means react-native-calendars wasn't installed properly. Run npx expo install react-native-calendars in the Rork terminal to fix it.

Events Disappear After Restarting the App

Double-check that AsyncStorage is correctly imported from @react-native-async-storage/async-storage. Verify the package is listed in your package.json.

DateTimePicker Looks Different on iOS vs. Android

This is expected — @react-native-community/datetimepicker uses each platform's native picker UI. If you want a consistent look across platforms, ask Rork to build a custom modal picker instead.


Taking It Further

Once you have the basics working, consider adding these features to make your app stand out:

Week and day views: Beyond the month view, adding a weekly timeline or daily hour-by-hour view makes the app feel much more professional and practical for power users.

Category tagging with color coding: Let users tag events as "Work," "Personal," "Health," etc., with distinct colors. This makes the calendar far more scannable at a glance.

Recurring events: Automatically generating weekly or monthly recurring events is a huge quality-of-life feature that users love.

Google Calendar sync: Using Expo's expo-calendar library, you can integrate with the device's native calendar for seamless two-way sync.


Wrapping Up

In this tutorial, we walked through building a calendar and schedule management app with Rork — from setting up the calendar UI and event forms, to persisting data with AsyncStorage, and adding reminder notifications.

Building a calendar app is an excellent way to practice core mobile development skills: component design, state management, and data persistence. Use what you've learned here as a foundation, and customize it into the perfect scheduling tool for your target audience.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Getting Started2026-05-05
Native App or PWA? Three Questions to Answer Before Building with Rork
Should you build a native app with Rork or go with a PWA? This guide breaks down the real functional differences — push notifications, camera, App Store distribution — and gives you a clear decision framework.
Getting Started2026-03-28
UX Design Patterns for Rork Apps — Screen Layouts, Micro-Interactions, and Practical Techniques to Dramatically Improve User Experience
A practical guide to dramatically improving the UX of apps built with Rork. Learn screen layout patterns, navigation design, micro-interactions, onboarding flows, and accessibility best practices to transform your AI-generated app into a professional-grade product.
Getting Started2026-03-23
How to Build a Pomodoro Timer App with Rork — A Complete Beginner's Tutorial
Learn how to build a fully functional Pomodoro timer app with Rork, step by step. Covers timer logic, session management, circular progress bars, and haptic notifications — all in under 30 minutes.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →