# V popover 18

> Confirmation / delete

A shadcn/ui block from the [@cnippet](https://ui.cnippet.dev/) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/cnippet/v-popover-18).

- Page, with a live preview: https://shadcn.exchange/r/cnippet/v-popover-18
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/cnippet/v-popover-18-light-fe7e0ac439e82356.png
- Registry item: https://ui.cnippet.dev/r/v-popover-18.json
- Categories: popover
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.cnippet.dev/r/v-popover-18.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: `@cnippet/popover`

## Files

### `registry/default/variants/v-popover-18.tsx`

```tsx
"use client";

import { PlusIcon, XIcon } from "lucide-react";
import { useState } from "react";
import { Badge } from "@/registry/default/ui/badge";
import { Button } from "@/registry/default/ui/button";
import { Input } from "@/registry/default/ui/input";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/registry/default/ui/popover";

const SUGGESTIONS = ["design", "engineering", "product", "research", "growth"];

export function Pattern() {
  const [tags, setTags] = useState(["react", "typescript"]);
  const [input, setInput] = useState("");

  function addTag(tag: string) {
    const trimmed = tag.trim().toLowerCase();
    if (trimmed && !tags.includes(trimmed)) setTags((p) => [...p, trimmed]);
    setInput("");
  }

  return (
    <div className="flex flex-wrap items-center gap-1.5">
      {tags.map((tag) => (
        <Badge className="gap-1 pr-1" key={tag} variant="secondary">
          {tag}
          <button
            aria-label={`Remove ${tag}`}
            className="rounded-full hover:bg-foreground/10"
            onClick={() => setTags((p) => p.filter((t) => t !== tag))}
            type="button"
          >
            <XIcon className="size-3" />
          </button>
        </Badge>
      ))}
      <Popover>
        <PopoverTrigger
          aria-label="Add tag"
          render={<Button className="size-6" size="icon" variant="ghost" />}
        >
          <PlusIcon className="size-3.5" />
        </PopoverTrigger>
        <PopoverContent className="w-52 gap-2" side="bottom">
          <Input
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter") {
                e.preventDefault();
                addTag(input);
              }
            }}
            placeholder="Add tag…"
            value={input}
          />
          <div className="space-y-0.5">
            {SUGGESTIONS.filter((s) => !tags.includes(s))
              .slice(0, 3)
              .map((s) => (
                <button
                  className="flex w-full items-center rounded px-2 py-1 text-sm hover:bg-muted"
                  key={s}
                  onClick={() => addTag(s)}
                  type="button"
                >
                  {s}
                </button>
              ))}
          </div>
        </PopoverContent>
      </Popover>
    </div>
  );
}
```
