# Reminder List

> A short reminder list you can search, check off and add to.

A shadcn/ui block from the [@cupertinoui](https://www.cupertino-ui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/cupertinoui/reminders-01).

- Page, with a live preview: https://shadcn.exchange/r/cupertinoui/reminders-01
- Screenshot: https://shadcn.exchange/shot/cupertinoui/reminders-01/light.png
- Registry item: https://www.cupertino-ui.com/r/reminders-01.json
- Listed: 2026-11-05, source last changed 2026-11-05

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/cupertinoui/reminders-01.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `@cupertinoui/macos-theme`, `@cupertinoui/button`, `@cupertinoui/checkbox`, `@cupertinoui/input`, `@cupertinoui/search-field`, `@cupertinoui/window`

## Files

### `registry/macos/blocks/reminders-01/reminders-01.tsx`

```tsx
"use client"

import * as React from "react"
import { PlusIcon } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/registry/macos/ui/button"
import { Checkbox } from "@/registry/macos/ui/checkbox"
import { Input } from "@/registry/macos/ui/input"
import { SearchField } from "@/registry/macos/ui/search-field"
import {
  Window,
  WindowContent,
  WindowControls,
  WindowMain,
  WindowTitle,
  WindowTitlebar,
} from "@/registry/macos/ui/window"

type Reminder = { id: number; title: string; done: boolean }

const initialReminders: Reminder[] = [
  { id: 1, title: "Ship the free blocks", done: false },
  { id: 2, title: "Reply to Maya", done: false },
  { id: 3, title: "Renew the domain", done: true },
  { id: 4, title: "Book a dentist appointment", done: false },
  { id: 5, title: "Export the October invoices", done: false },
]

// A short reminder list: search, check off, and add a new one.
export function Reminders01({
  className,
  ...props
}: React.ComponentProps<typeof Window>) {
  const [reminders, setReminders] = React.useState(initialReminders)
  const [query, setQuery] = React.useState("")
  const [draft, setDraft] = React.useState("")
  const nextId = React.useRef(initialReminders.length + 1)

  const needle = query.trim().toLowerCase()
  const visible = reminders.filter((item) => item.title.toLowerCase().includes(needle))

  function toggle(id: number, done: boolean) {
    setReminders((current) =>
      current.map((item) => (item.id === id ? { ...item, done } : item))
    )
  }

  return (
    <Window className={cn("h-[480px] w-[340px]", className)} {...props}>
      <WindowMain>
        <WindowTitlebar>
          <WindowControls />
          <WindowTitle>Reminders</WindowTitle>
        </WindowTitlebar>
        <WindowContent className="flex flex-col overflow-hidden">
          <div className="px-3 pt-3 pb-2">
            <SearchField
              value={query}
              onChange={(event) => setQuery(event.target.value)}
              placeholder="Search"
              aria-label="Search reminders"
              className="w-full"
            />
          </div>
          <div className="min-h-0 flex-1 overflow-auto px-1.5 pb-1">
            {visible.length === 0 ? (
              <p className="px-3 py-8 text-center text-mac-body text-mac-label-secondary">
                {reminders.length === 0 ? "No reminders yet" : "No matching reminders"}
              </p>
            ) : (
              <ul>
                {visible.map((item) => (
                  <li key={item.id}>
                    <label className="flex cursor-default items-center gap-2.5 rounded-[6px] px-2.5 py-[7px] hover:bg-mac-fill-quaternary">
                      <Checkbox
                        checked={item.done}
                        onCheckedChange={(checked) => toggle(item.id, checked === true)}
                        aria-label={item.title}
                      />
                      <span
                        className={cn(
                          "min-w-0 truncate text-mac-body",
                          item.done && "text-mac-label-tertiary line-through"
                        )}
                      >
                        {item.title}
                      </span>
                    </label>
                  </li>
                ))}
              </ul>
            )}
          </div>
          <form
            className="flex items-center gap-2 border-t border-mac-separator px-3 py-2.5"
            onSubmit={(event) => {
              event.preventDefault()
              const title = draft.trim()
              if (!title) return
              const id = nextId.current++
              setReminders((current) => [...current, { id, title, done: false }])
              setDraft("")
              setQuery("")
            }}
          >
            <Input
              value={draft}
              onChange={(event) => setDraft(event.target.value)}
              placeholder="New Reminder"
              aria-label="New reminder"
            />
            <Button
              type="submit"
              size="icon"
              variant="secondary"
              disabled={!draft.trim()}
              aria-label="Add reminder"
            >
              <PlusIcon />
            </Button>
          </form>
        </WindowContent>
      </WindowMain>
    </Window>
  )
}
```
