# Delete Resource

Resource name confirmation with asynchronous deletion, pending state, and retryable errors.

Page: https://sui.draco.dev/docs/blocks/delete-resource

Inspired by [Kumo Delete Resource](https://kumo-ui.com/blocks/delete-resource/), this block composes SUI AlertDialog, Field, Input, and Button. It requires the resource name before invoking the deletion callback.

## Name confirmation

Open the dialog and type `sui-preview`. The destructive action enables only when the input matches. Deletion keeps controls disabled until the callback finishes. The resource name in the confirmation hint has an inline copy action. Copying does not populate the confirmation field or submit the form; it is disabled during deletion.

### Example: block-delete-resource

```tsx
import { DeleteResource } from "@workspace/ui/blocks/delete-resource";
import { Button } from "@workspace/ui/components/button";
import { useState } from "react";
import type { ExampleProps } from "../types";

export default function DeleteResourceDemo({ locale }: ExampleProps) {
  const zh = locale === "zh-CN";
  const [open, setOpen] = useState(false);
  const [deleted, setDeleted] = useState(false);
  return (
    <div className="flex flex-col items-center gap-3">
      <Button
        variant="destructive"
        onClick={() => {
          setDeleted(false);
          setOpen(true);
        }}
      >
        {zh ? "删除项目" : "Delete project"}
      </Button>
      <DeleteResource
        open={open}
        onOpenChange={setOpen}
        resourceType="project"
        resourceName="sui-preview"
        onDelete={async () => {
          await new Promise((resolve) => setTimeout(resolve, 600));
          setDeleted(true);
        }}
        labels={
          zh
            ? {
                title: "删除项目？",
                description: "将永久删除 sui-preview，此操作无法撤销。",
                confirmation: "项目名称",
                copy: "复制资源名称",
                copying: "正在复制…",
                copied: "已复制",
                copyFailed: "复制失败，请选择名称手动复制。",
                hint: "输入 sui-preview 确认删除。",
                delete: "删除项目",
                cancel: "取消",
                deleting: "正在删除…",
              }
            : undefined
        }
      />
      {deleted && (
        <p role="status" className="text-muted-foreground text-sm">
          {zh ? "项目已删除" : "Project deleted"}
        </p>
      )}
    </div>
  );
}
```

## Failure and retry

The first attempt fails in this example. The dialog preserves the confirmation, displays the error, and allows a second attempt. Reopening clears the previous confirmation and error.

### Example: block-delete-resource-error

```tsx
import { DeleteResource } from "@workspace/ui/blocks/delete-resource";
import { Button } from "@workspace/ui/components/button";
import { useRef, useState } from "react";
import type { ExampleProps } from "../types";

export default function DeleteResourceError({ locale }: ExampleProps) {
  const zh = locale === "zh-CN";
  const [open, setOpen] = useState(false);
  const attempts = useRef(0);
  return (
    <>
      <Button
        variant="destructive"
        onClick={() => {
          attempts.current = 0;
          setOpen(true);
        }}
      >
        {zh ? "删除并重试" : "Delete with retry"}
      </Button>
      <DeleteResource
        open={open}
        onOpenChange={setOpen}
        resourceType="worker"
        resourceName="api-gateway"
        onDelete={async () => {
          await new Promise((resolve) => setTimeout(resolve, 600));
          attempts.current += 1;
          if (attempts.current === 1)
            throw new Error(
              zh
                ? "暂时无法删除。请重试。"
                : "Unable to delete right now. Please try again.",
            );
        }}
        labels={
          zh
            ? {
                title: "删除 Worker？",
                description: "将永久删除 api-gateway，此操作无法撤销。",
                confirmation: "Worker 名称",
                copy: "复制资源名称",
                copying: "正在复制…",
                copied: "已复制",
                copyFailed: "复制失败，请选择名称手动复制。",
                hint: "输入 api-gateway 确认删除。",
                delete: "删除 Worker",
                cancel: "取消",
                deleting: "正在删除…",
              }
            : undefined
        }
      />
    </>
  );
}
```

## Case-insensitive confirmation

Set `caseSensitive={false}` when confirmation should ignore letter case.

### Example: block-delete-resource-insensitive

```tsx
import { DeleteResource } from "@workspace/ui/blocks/delete-resource";
import { Button } from "@workspace/ui/components/button";
import { useState } from "react";
import type { ExampleProps } from "../types";

export default function DeleteResourceInsensitive({ locale }: ExampleProps) {
  const zh = locale === "zh-CN";
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button variant="destructive" onClick={() => setOpen(true)}>
        {zh ? "删除域名" : "Delete domain"}
      </Button>
      <DeleteResource
        open={open}
        onOpenChange={setOpen}
        resourceType="domain"
        resourceName="Example.com"
        caseSensitive={false}
        onDelete={() => {}}
        labels={
          zh
            ? {
                title: "删除域名？",
                description: "将永久删除 Example.com，此操作无法撤销。",
                confirmation: "域名",
                copy: "复制资源名称",
                copying: "正在复制…",
                copied: "已复制",
                copyFailed: "复制失败，请选择名称手动复制。",
                hint: "输入 Example.com 确认，不区分大小写。",
                delete: "删除域名",
                cancel: "取消",
              }
            : { hint: "Type Example.com to confirm (case insensitive)." }
        }
      />
    </>
  );
}
```

## Installation

```bash
bunx --bun shadcn@latest add @sui/delete-resource
```

Install this Block with the shadcn CLI command above. Follow the [installation guide](/docs/installation) for registry, dependency, and style setup. The examples below use workspace imports; registry-installed source uses the aliases configured in the consuming application's `components.json`.

## Usage

```tsx
import { DeleteResource } from "@workspace/ui/blocks/delete-resource"

<DeleteResource
  open={open}
  onOpenChange={setOpen}
  resourceType="project"
  resourceName="sui-preview"
  onDelete={async () => { await deleteProject("sui-preview") }}
/>
```

The block keeps English defaults. Resolve translations in your application and pass them through `labels`; translate any callback error messages there too.

## API

| Prop | Default | Description |
| --- | --- | --- |
| `open`, `onOpenChange` | Required | Controlled visibility. |
| `resourceType`, `resourceName` | Required | Resource identity and confirmation target. Empty names cannot be confirmed. |
| `onDelete` | Required | Sync or async deletion callback. Resolve on success; throw on failure. |
| `caseSensitive` | `true` | Whether confirmation distinguishes case. Whitespace must match exactly. |
| `isDeleting` | `false` | Optional external pending state; combined with internal submission state. |
| `errorMessage` | — | Optional error from the application. |
| `description` | Generated | Custom explanatory content. |
| `labels` | English | Override title, description, confirmation, hint, cancel, delete, deleting, failed, copy, copying, copied, and copyFailed text. |
| `className` | — | Dialog layout classes. |

On success the block calls `onOpenChange(false)`. On failure it stays open. Duplicate submission and closing are blocked while deletion is pending. The application owns the actual delete operation; these previews only simulate it.
