diff --git a/docs/.vuepress/components/timeoutExample.vue b/docs/.vuepress/components/timeoutExample.vue
new file mode 100644
index 000000000..612ae0c0f
--- /dev/null
+++ b/docs/.vuepress/components/timeoutExample.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/composable/web/timeout.md b/docs/composable/web/timeout.md
new file mode 100644
index 000000000..03dad9c13
--- /dev/null
+++ b/docs/composable/web/timeout.md
@@ -0,0 +1,85 @@
+# Timeout
+
+> The [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout).
+
+## Parameters
+
+```js
+import { useTimeout } from "vue-composable";
+
+useTimeout(fn, delay);
+```
+
+| Parameters | Type | Required | Default | Description |
+| ---------- | ---------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------- |
+| fn | `Function` | `true` | | A function to be executed after the timer expires. |
+| delay | `Number` | `false` | `0 ` | The time, in milliseconds (thousandths of a second), the timer should wait before the specified function is executed. |
+
+## State
+
+The `useTimeout` function exposes the following reactive state:
+
+```js
+import { useTimeout } from "vue-composable";
+
+const { ready } = useTimeout(fn, delay);
+```
+
+| State | Type | Description |
+| ----- | ------------ | ----------- | ---------------------------------------------------------------------------------------------------- |
+| ready | `Ref` | current timeout state:
false - pending
true - called
null - canceled |
+
+## Methods
+
+The `useTimeout` function exposes the following methods:
+
+```js
+import { useTimeout } from "vue-composable";
+
+const { cancel } = useTimeout(fn, delay);
+```
+
+| Signature | Description |
+| --------- | ------------------ |
+| `cancel` | cancel the timeout |
+
+## Example
+
+
+
+### Code
+
+```vue
+
+
+
+
+
+
+
+
+
+```
diff --git a/packages/vue-composable/__tests__/web/timeout.spec.ts b/packages/vue-composable/__tests__/web/timeout.spec.ts
new file mode 100644
index 000000000..7ea1dac93
--- /dev/null
+++ b/packages/vue-composable/__tests__/web/timeout.spec.ts
@@ -0,0 +1,80 @@
+import { useTimeout } from "../../src";
+import { createVue } from "../utils";
+import { Ref, ref } from "../../src/api";
+
+describe("timeout", () => {
+ jest.useFakeTimers();
+ it("should be defined", () => {
+ expect(useTimeout).toBeDefined();
+ });
+
+ it("should call passed function after given amount of time", async () => {
+ let count = 0;
+ useTimeout(() => {
+ count++;
+ }, 1000);
+
+ expect(count).toBe(0);
+ jest.advanceTimersByTime(900);
+ // should not be resolved
+ expect(count).toBe(0);
+
+ jest.advanceTimersByTime(100);
+ expect(count).toBe(1);
+ });
+
+ it("should set ready true after run callback", async () => {
+ const { ready } = useTimeout(() => {}, 1000);
+
+ expect(ready.value).toBe(false);
+ jest.advanceTimersByTime(1000);
+ expect(ready.value).toBe(true);
+ });
+
+ it("should cancel function call when call cancel function", async () => {
+ let count = 0;
+ const { ready, cancel } = useTimeout(() => {
+ count++;
+ }, 1000);
+
+ expect(ready.value).toBe(false);
+ expect(count).toBe(0);
+
+ cancel();
+
+ jest.advanceTimersByTime(1000);
+ expect(ready.value).toBe(null);
+ expect(count).toBe(0);
+ });
+
+ it("should cancel on unMounted", async () => {
+ let ready: Ref = ref(false);
+
+ const { mount, destroy } = createVue({
+ template: ``,
+ setup() {
+ ready = useTimeout(() => {}, 1000).ready;
+ },
+ });
+
+ mount();
+
+ expect(ready.value).toBe(false);
+ jest.advanceTimersByTime(500);
+ expect(ready.value).toBe(false);
+
+ destroy();
+ expect(ready.value).toBe(null);
+ });
+
+ it("should default the delay to 0", () => {
+ let count = 0;
+ useTimeout(() => {
+ count++;
+ });
+
+ expect(count).toBe(0);
+ jest.runOnlyPendingTimers();
+ expect(count).toBe(1);
+ });
+});
diff --git a/packages/vue-composable/src/web/index.ts b/packages/vue-composable/src/web/index.ts
index 7147045aa..cf304be7c 100644
--- a/packages/vue-composable/src/web/index.ts
+++ b/packages/vue-composable/src/web/index.ts
@@ -11,4 +11,5 @@ export * from "./cssVariables";
export * from "./worker";
export * from "./share";
export * from "./clipboard";
+export * from "./timeout";
export { useWorkerFunction, WebWorkerFunctionOptions } from "./workerFunction";
diff --git a/packages/vue-composable/src/web/timeout.ts b/packages/vue-composable/src/web/timeout.ts
new file mode 100644
index 000000000..358f337b2
--- /dev/null
+++ b/packages/vue-composable/src/web/timeout.ts
@@ -0,0 +1,43 @@
+import { ref, Ref, onUnmounted } from "../api";
+
+interface UseTimeoutReturn {
+ /**
+ * current timeout state:
+ * false - pending
+ * true - called
+ * null - canceled
+ */
+ ready: Ref;
+ /**
+ * cancel the timeout
+ */
+ cancel: () => void;
+}
+/**
+ * @param fn setTimeout callback
+ * @param delay If this parameter is omitted, a value of 0 is used
+ * (https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)
+ */
+export function useTimeout(
+ fn: () => void,
+ delay: number = 0
+): UseTimeoutReturn {
+ let ready: Ref = ref(false);
+
+ const timeoutId = setTimeout(() => {
+ ready.value = true;
+ fn();
+ }, delay);
+
+ const cancel = () => {
+ ready.value = null;
+ clearTimeout(timeoutId);
+ };
+
+ onUnmounted(cancel);
+
+ return {
+ ready,
+ cancel,
+ };
+}