diff --git a/src/components/CopyCurlButton.test.tsx b/src/components/CopyCurlButton.test.tsx
new file mode 100644
index 0000000..8b5ad5e
--- /dev/null
+++ b/src/components/CopyCurlButton.test.tsx
@@ -0,0 +1,49 @@
+// @vitest-environment jsdom
+
+import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import CopyCurlButton from "./CopyCurlButton";
+
+describe("CopyCurlButton", () => {
+ beforeEach(() => {
+ Object.assign(navigator, {
+ clipboard: { writeText: vi.fn().mockResolvedValue(undefined) },
+ });
+ });
+
+ afterEach(() => {
+ cleanup();
+ vi.restoreAllMocks();
+ });
+
+ it("renders an accessible default label", () => {
+ render();
+ expect(
+ screen.getByRole("button", { name: /copy request as a curl command/i }),
+ ).toBeTruthy();
+ expect(screen.getByText("Copy as cURL")).toBeTruthy();
+ });
+
+ it("writes the cURL command to the clipboard on click", async () => {
+ const writeText = navigator.clipboard.writeText as ReturnType;
+ render(
+ ,
+ );
+ fireEvent.click(screen.getByRole("button"));
+ await waitFor(() => expect(writeText).toHaveBeenCalledTimes(1));
+ const copied = writeText.mock.calls[0][0] as string;
+ expect(copied).toContain("curl -X POST 'https://x.test/echo'");
+ expect(copied).toContain('--data \'{"a":1}\'');
+ });
+
+ it("shows success feedback after copying", async () => {
+ render();
+ fireEvent.click(screen.getByRole("button"));
+ await waitFor(() => expect(screen.getByText("Copied")).toBeTruthy());
+ expect(
+ screen.getByText("cURL command copied to clipboard"),
+ ).toBeTruthy();
+ });
+});
diff --git a/src/components/CopyCurlButton.tsx b/src/components/CopyCurlButton.tsx
new file mode 100644
index 0000000..80341cd
--- /dev/null
+++ b/src/components/CopyCurlButton.tsx
@@ -0,0 +1,119 @@
+import { useEffect, useRef, useState } from "react";
+import { toCurl, type CurlRequest } from "../utils/toCurl";
+
+/**
+ * CopyCurlButton — copies a request to the clipboard as a ready-to-run `curl`
+ * command and gives clear, accessible success feedback (issue #284).
+ *
+ * Accessibility (WCAG 2.1 AA):
+ * - Real