diff --git a/src/hooks/useIsClient/index.ts b/src/hooks/useIsClient/index.ts
new file mode 100644
index 0000000..b8d9782
--- /dev/null
+++ b/src/hooks/useIsClient/index.ts
@@ -0,0 +1 @@
+export { useIsClient } from './useIsClient.ts';
diff --git a/src/hooks/useIsClient/useIsClient.spec.tsx b/src/hooks/useIsClient/useIsClient.spec.tsx
new file mode 100644
index 0000000..22c4eb2
--- /dev/null
+++ b/src/hooks/useIsClient/useIsClient.spec.tsx
@@ -0,0 +1,32 @@
+import { render, screen } from '@testing-library/react';
+import { describe, expect, it } from 'vitest';
+
+import { renderSSR } from '../../_internal/test-utils/renderSSR.tsx';
+
+import { useIsClient } from './useIsClient.ts';
+
+function TestComponent() {
+ const isClient = useIsClient();
+
+ return
{isClient ? 'Client-side' : 'Server-side'}
;
+}
+
+describe('useIsClient', () => {
+ it('should render "Server-side" text when rendered in a server environment (SSR)', () => {
+ renderSSR.serverOnly(() => );
+
+ expect(screen.getByText('Server-side')).toBeInTheDocument();
+ });
+
+ it('should update to "Client-side" text after hydration on the client', async () => {
+ await renderSSR(() => );
+
+ expect(screen.getByText('Client-side')).toBeInTheDocument();
+ });
+
+ it('should render "Client-side" text when mounted directly on the client', async () => {
+ render();
+
+ expect(screen.getByText('Client-side')).toBeInTheDocument();
+ });
+});
diff --git a/src/hooks/useIsClient/useIsClient.ts b/src/hooks/useIsClient/useIsClient.ts
new file mode 100644
index 0000000..ec01cfc
--- /dev/null
+++ b/src/hooks/useIsClient/useIsClient.ts
@@ -0,0 +1,46 @@
+import { useEffect, useState } from 'react';
+
+/**
+ * @description
+ * `useIsClient` is a React hook that returns `true` only in the client-side environment.
+ * It is primarily used to differentiate between client-side and server-side rendering (SSR).
+ * The state is set to `true` only after the component is mounted in the client-side environment.
+ *
+ * @returns {boolean} Returns `true` in a client-side environment, and `false` otherwise.
+ *
+ * @example
+ * function ClientSideContent() {
+ * const isClient = useIsClient();
+ *
+ * if (!isClient) {
+ * return Loading...
; // Rendered on the server side
+ * }
+ *
+ * return Client-side rendered content
; // Rendered on the client side
+ * }
+ *
+ * @example
+ * function ClientOnlyMap() {
+ * const isClient = useIsClient();
+ *
+ * if (!isClient) return null;
+ *
+ * return ;
+ * }
+ *
+ * @example
+ * function ClientTheme() {
+ * const isClient = useIsClient();
+ *
+ * const theme = isClient ? localStorage.getItem('theme') : 'light';
+ *
+ * return Current theme: {theme}
;
+ * }
+ */
+export function useIsClient() {
+ const [isClient, setIsClient] = useState(false);
+
+ useEffect(() => setIsClient(true), []);
+
+ return isClient;
+}
diff --git a/src/index.ts b/src/index.ts
index 5a5911d..d48d043 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -13,6 +13,7 @@ export { useImpressionRef } from './hooks/useImpressionRef/index.ts';
export { useInputState } from './hooks/useInputState/index.ts';
export { useIntersectionObserver } from './hooks/useIntersectionObserver/index.ts';
export { useInterval } from './hooks/useInterval/index.ts';
+export { useIsClient } from './hooks/useIsClient/index.ts';
export { useIsomorphicLayoutEffect } from './hooks/useIsomorphicLayoutEffect/index.ts';
export { useLoading } from './hooks/useLoading/index.ts';
export { useOutsideClickEffect } from './hooks/useOutsideClickEffect/index.ts';