# Save

> A save dialog with a file name, a folder pop-up, optional tags, and Cancel and Save.

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/save-panel-01).

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

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/cupertinoui/save-panel-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

- Registry items: `@cupertinoui/macos-theme`, `@cupertinoui/button`, `@cupertinoui/input`, `@cupertinoui/label`, `@cupertinoui/select`, `@cupertinoui/window`

## Files

### `registry/macos/blocks/save-panel-01/save-panel-01.tsx`

```tsx
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import { Button } from "@/registry/macos/ui/button"
import { Input } from "@/registry/macos/ui/input"
import { Label } from "@/registry/macos/ui/label"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/registry/macos/ui/select"
import {
  Window,
  WindowContent,
  WindowControls,
  WindowMain,
  WindowTitle,
  WindowTitlebar,
} from "@/registry/macos/ui/window"

const folders = {
  documents: "Documents",
  desktop: "Desktop",
  downloads: "Downloads",
  icloud: "iCloud Drive",
} as const

type Folder = keyof typeof folders

// A save dialog: file name, destination, tags, then Cancel and Save.
export function SavePanel01({
  className,
  ...props
}: React.ComponentProps<typeof Window>) {
  const nameId = React.useId()
  const tagsId = React.useId()
  const [name, setName] = React.useState("Untitled.tsx")
  const [folder, setFolder] = React.useState<Folder>("documents")
  const [tags, setTags] = React.useState("")
  const [saved, setSaved] = React.useState(false)

  return (
    <Window className={cn("h-[220px] w-[440px]", className)} {...props}>
      <WindowMain>
        <WindowTitlebar>
          <WindowControls />
          <WindowTitle>Save</WindowTitle>
        </WindowTitlebar>
        <WindowContent className="flex flex-col px-5 py-4">
          {saved ? (
            <div className="flex flex-1 flex-col">
              <div className="flex flex-1 flex-col items-center justify-center text-center">
                <p className="text-mac-body font-semibold">Saved</p>
                <p className="mt-1 text-mac-subheadline text-mac-label-secondary">
                  {name} in {folders[folder]}
                  {tags ? `, tagged ${tags}` : ""}
                </p>
              </div>
              <div className="flex justify-end">
                <Button onClick={() => setSaved(false)}>Done</Button>
              </div>
            </div>
          ) : (
            <form
              className="flex flex-1 flex-col"
              onSubmit={(event) => {
                event.preventDefault()
                setSaved(true)
              }}
            >
              <div className="grid grid-cols-[72px_1fr] items-center gap-x-3 gap-y-3">
                <Label htmlFor={nameId} className="justify-end text-mac-label-secondary">
                  Save As:
                </Label>
                <Input
                  id={nameId}
                  value={name}
                  onChange={(event) => setName(event.target.value)}
                  required
                />
                <span className="justify-self-end text-mac-body text-mac-label-secondary">Where:</span>
                <Select
                  value={folder}
                  onValueChange={(value) => value && setFolder(value as Folder)}
                  items={folders}
                >
                  <SelectTrigger className="w-full" aria-label="Where">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    {(Object.keys(folders) as Folder[]).map((value) => (
                      <SelectItem key={value} value={value}>
                        {folders[value]}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <Label htmlFor={tagsId} className="justify-end text-mac-label-secondary">
                  Tags:
                </Label>
                <Input
                  id={tagsId}
                  value={tags}
                  onChange={(event) => setTags(event.target.value)}
                  placeholder="Optional"
                />
              </div>
              <div className="mt-auto flex justify-end gap-2">
                <Button
                  type="button"
                  variant="secondary"
                  onClick={() => {
                    setName("Untitled.tsx")
                    setTags("")
                    setFolder("documents")
                  }}
                >
                  Cancel
                </Button>
                <Button type="submit">Save</Button>
              </div>
            </form>
          )}
        </WindowContent>
      </WindowMain>
    </Window>
  )
}
```
