diff --git a/react-ux-semantics-docs/docs/docs/click-to-copy.md b/react-ux-semantics-docs/docs/docs/click-to-copy.md
new file mode 100644
index 0000000..63a0303
--- /dev/null
+++ b/react-ux-semantics-docs/docs/docs/click-to-copy.md
@@ -0,0 +1,41 @@
+---
+sidebar_position: 3
+title: Click to copy
+---
+
+## General description
+
+Hook that allows you to implement copy-by-click semantic – when user clicks on the interface element and gets some predefined text copied to clipboard.
+
+## Usage example
+
+```jsx
+export const ComponentWithCopyableText = () => {
+ const text = 'This text will be copied!';
+ const [ clickHandler, copyPromise ] = useClickToCopy(text);
+
+ return (
+ <>
+
{text}
+
+ >
+ )
+};
+```
+
+## API
+
+### useClickToCopy
+
+```ts
+declare function useClickToCopy(text: string): [() => void, Promise];
+```
+
+#### Arguments
+
+|arg|type|description|
+|:--|:---|:----------|
+|`text`|`string`|Text to copy|
+
+
+Returns a tuple with handler for a trigger and promise, which will be resolve when the text will be copied.
\ No newline at end of file
diff --git a/react-ux-semantics/src/click-to-copy/index.ts b/react-ux-semantics/src/click-to-copy/index.ts
new file mode 100644
index 0000000..cf41ed8
--- /dev/null
+++ b/react-ux-semantics/src/click-to-copy/index.ts
@@ -0,0 +1,16 @@
+import { useCallback } from "react";
+
+export function useClickToCopy(text: string): [() => void, Promise] {
+ let resolver: () => void;
+ const promise = new Promise((resolve) => {
+ resolver = resolve;
+ });
+
+ const handler = useCallback(async () => {
+ await navigator.clipboard.writeText(text);
+
+ resolver();
+ }, [text, resolver]);
+
+ return [handler, promise];
+}
diff --git a/react-ux-semantics/src/index.ts b/react-ux-semantics/src/index.ts
index 9e37f35..854c701 100644
--- a/react-ux-semantics/src/index.ts
+++ b/react-ux-semantics/src/index.ts
@@ -1,2 +1,3 @@
export { useAutohide } from "./autohide";
+export { useClickToCopy } from "./click-to-copy";
export { useShowable } from "./showable";
diff --git a/react-ux-semantics/tests/click-to-copy.test.ts b/react-ux-semantics/tests/click-to-copy.test.ts
new file mode 100644
index 0000000..c33c24f
--- /dev/null
+++ b/react-ux-semantics/tests/click-to-copy.test.ts
@@ -0,0 +1,44 @@
+import { describe, it, vi, expect, afterEach } from "vitest";
+import { renderHook, act } from "@testing-library/react";
+
+import { useClickToCopy } from "../src/click-to-copy";
+
+type DeepPartial = T extends object
+ ? {
+ [P in keyof T]?: DeepPartial;
+ }
+ : T;
+
+const navigatorMock: DeepPartial = {
+ clipboard: {
+ writeText: vi.fn(() => Promise.resolve()),
+ },
+};
+
+vi.stubGlobal("navigator", navigatorMock);
+
+describe("click to copy", () => {
+ afterEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("should call clipboard method of we API when handler is called", async () => {
+ const { result } = renderHook(() => useClickToCopy("henlo, fren!"));
+ const [handler] = result.current;
+
+ await act(() => handler());
+
+ expect(navigatorMock.clipboard?.writeText).toHaveBeenCalledWith(
+ "henlo, fren!",
+ );
+ });
+
+ it("should resolve promise when text was copied to clipboard", async () => {
+ const { result } = renderHook(() => useClickToCopy("henlo, fren!"));
+ const [handler, promise] = result.current;
+
+ await act(() => handler());
+
+ await expect(promise).resolves.toBeFalsy();
+ });
+});