diff --git a/packages/react/components/Tabs.tsx b/packages/react/components/Tabs/Component.tsx
similarity index 59%
rename from packages/react/components/Tabs.tsx
rename to packages/react/components/Tabs/Component.tsx
index 3214bda..bc90902 100644
--- a/packages/react/components/Tabs.tsx
+++ b/packages/react/components/Tabs/Component.tsx
@@ -1,30 +1,7 @@
 import { AsChild, Slot, VariantProps, vcn } from "@pswui-lib";
 import React from "react";
 
-interface Tab {
-  name: string;
-}
-
-interface TabContextBody {
-  tabs: Tab[];
-  active: [number, string] /* index, name */;
-}
-
-const TabContext = React.createContext<
-  [TabContextBody, React.Dispatch<React.SetStateAction<TabContextBody>>]
->([
-  {
-    tabs: [],
-    active: [0, ""],
-  },
-  () => {
-    if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
-      console.warn(
-        "It seems like you're using TabContext outside of provider.",
-      );
-    }
-  },
-]);
+import { TabContextBody, TabContext, Tab } from "./Context";
 
 interface TabProviderProps {
   defaultName: string;
@@ -40,77 +17,6 @@ const TabProvider = ({ defaultName, children }: TabProviderProps) => {
   return <TabContext.Provider value={state}>{children}</TabContext.Provider>;
 };
 
-/**
- * Provides current state for tab, using context.
- * Also provides functions to control state.
- */
-const useTabState = () => {
-  const [state, setState] = React.useContext(TabContext);
-
-  function getActiveTab() {
-    return state.active;
-  }
-
-  function setActiveTab(name: string): void;
-  function setActiveTab(index: number): void;
-  function setActiveTab(param: string | number) {
-    if (typeof param === "number") {
-      if (param < 0 || param >= state.tabs.length) {
-        if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
-          console.error(
-            `Invalid index passed to setActiveTab: ${param}, valid indices are 0 to ${
-              state.tabs.length - 1
-            }`,
-          );
-        }
-        return;
-      }
-
-      setState((prev) => {
-        return {
-          ...prev,
-          active: [param, prev.tabs[param].name],
-        };
-      });
-    } else if (typeof param === "string") {
-      const index = state.tabs.findIndex((tab) => tab.name === param);
-      if (index === -1) {
-        if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
-          console.error(
-            `Invalid name passed to setActiveTab: ${param}, valid names are ${state.tabs
-              .map((tab) => tab.name)
-              .join(", ")}`,
-          );
-        }
-        return;
-      }
-
-      setActiveTab(index);
-    }
-  }
-
-  function setPreviousActive() {
-    if (state.active[0] === 0) {
-      return;
-    }
-    setActiveTab(state.active[0] - 1);
-  }
-
-  function setNextActive() {
-    if (state.active[0] === state.tabs.length - 1) {
-      return;
-    }
-    setActiveTab(state.active[0] + 1);
-  }
-
-  return {
-    getActiveTab,
-    setActiveTab,
-    setPreviousActive,
-    setNextActive,
-  };
-};
-
 const [TabListVariant, resolveTabListVariantProps] = vcn({
   base: "flex flex-row bg-gray-100 dark:bg-neutral-800 rounded-lg p-1.5 gap-1",
   variants: {},
@@ -227,4 +133,4 @@ const TabContent = (props: TabContentProps) => {
   }
 };
 
-export { TabProvider, useTabState, TabList, TabTrigger, TabContent };
+export { TabProvider, TabList, TabTrigger, TabContent };
diff --git a/packages/react/components/Tabs/Context.ts b/packages/react/components/Tabs/Context.ts
new file mode 100644
index 0000000..4f00846
--- /dev/null
+++ b/packages/react/components/Tabs/Context.ts
@@ -0,0 +1,26 @@
+import React from "react";
+
+export interface Tab {
+  name: string;
+}
+
+export interface TabContextBody {
+  tabs: Tab[];
+  active: [number, string] /* index, name */;
+}
+
+export const TabContext = React.createContext<
+  [TabContextBody, React.Dispatch<React.SetStateAction<TabContextBody>>]
+>([
+  {
+    tabs: [],
+    active: [0, ""],
+  },
+  () => {
+    if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
+      console.warn(
+        "It seems like you're using TabContext outside of provider.",
+      );
+    }
+  },
+]);
diff --git a/packages/react/components/Tabs/Hook.ts b/packages/react/components/Tabs/Hook.ts
new file mode 100644
index 0000000..26e2aa3
--- /dev/null
+++ b/packages/react/components/Tabs/Hook.ts
@@ -0,0 +1,74 @@
+import React from "react";
+
+import { TabContext } from "./Context";
+
+/**
+ * Provides current state for tab, using context.
+ * Also provides functions to control state.
+ */
+export const useTabState = () => {
+  const [state, setState] = React.useContext(TabContext);
+
+  function getActiveTab() {
+    return state.active;
+  }
+
+  function setActiveTab(name: string): void;
+  function setActiveTab(index: number): void;
+  function setActiveTab(param: string | number) {
+    if (typeof param === "number") {
+      if (param < 0 || param >= state.tabs.length) {
+        if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
+          console.error(
+            `Invalid index passed to setActiveTab: ${param}, valid indices are 0 to ${
+              state.tabs.length - 1
+            }`,
+          );
+        }
+        return;
+      }
+
+      setState((prev) => {
+        return {
+          ...prev,
+          active: [param, prev.tabs[param].name],
+        };
+      });
+    } else if (typeof param === "string") {
+      const index = state.tabs.findIndex((tab) => tab.name === param);
+      if (index === -1) {
+        if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
+          console.error(
+            `Invalid name passed to setActiveTab: ${param}, valid names are ${state.tabs
+              .map((tab) => tab.name)
+              .join(", ")}`,
+          );
+        }
+        return;
+      }
+
+      setActiveTab(index);
+    }
+  }
+
+  function setPreviousActive() {
+    if (state.active[0] === 0) {
+      return;
+    }
+    setActiveTab(state.active[0] - 1);
+  }
+
+  function setNextActive() {
+    if (state.active[0] === state.tabs.length - 1) {
+      return;
+    }
+    setActiveTab(state.active[0] + 1);
+  }
+
+  return {
+    getActiveTab,
+    setActiveTab,
+    setPreviousActive,
+    setNextActive,
+  };
+};
diff --git a/packages/react/components/Tabs/index.ts b/packages/react/components/Tabs/index.ts
new file mode 100644
index 0000000..c16790c
--- /dev/null
+++ b/packages/react/components/Tabs/index.ts
@@ -0,0 +1,2 @@
+export * from "./Component";
+export * from "./Hook";