diff --git a/src/app.ts b/src/app.ts
index 2321374..b5233df 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -47,7 +47,11 @@ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
export { PostMessageTransport } from "./message-transport";
export * from "./types";
-export { applyHostStyles } from "./styles";
+export {
+ applyHostStyles,
+ getDocumentTheme,
+ applyDocumentTheme,
+} from "./styles";
/**
* Metadata key for associating a resource URI with a tool call.
diff --git a/src/react/index.tsx b/src/react/index.tsx
index 82867df..09e3b87 100644
--- a/src/react/index.tsx
+++ b/src/react/index.tsx
@@ -10,6 +10,7 @@
*
* - {@link useApp} - React hook to create and connect an MCP App
* - {@link useHostStyles} - React hook to apply host styles as CSS variables
+ * - {@link useDocumentTheme} - React hook for reactive document theme
* - {@link useAutoResize} - React hook for manual auto-resize control (rarely needed)
*
* @module @modelcontextprotocol/ext-apps/react
@@ -33,4 +34,5 @@
*/
export * from "./useApp";
export * from "./useAutoResize";
+export * from "./useDocumentTheme";
export * from "./useHostStyles";
diff --git a/src/react/useDocumentTheme.ts b/src/react/useDocumentTheme.ts
new file mode 100644
index 0000000..2355c68
--- /dev/null
+++ b/src/react/useDocumentTheme.ts
@@ -0,0 +1,69 @@
+import { useEffect, useState } from "react";
+import { getDocumentTheme } from "../styles";
+import { McpUiTheme } from "../types";
+
+/**
+ * React hook that provides the current document theme reactively.
+ *
+ * Uses a MutationObserver to watch for changes to the `data-theme` attribute
+ * or `class` on `document.documentElement`. When the theme changes (e.g., from
+ * host context updates), the hook automatically re-renders your component with
+ * the new theme value.
+ *
+ * @returns The current theme ("light" or "dark")
+ *
+ * @example Conditionally render based on theme
+ * ```tsx
+ * import { useDocumentTheme } from '@modelcontextprotocol/ext-apps/react';
+ *
+ * function MyApp() {
+ * const theme = useDocumentTheme();
+ *
+ * return (
+ *
+ * {theme === 'dark' ? : }
+ *
+ * );
+ * }
+ * ```
+ *
+ * @example Use with theme-aware styling
+ * ```tsx
+ * function ThemedButton() {
+ * const theme = useDocumentTheme();
+ *
+ * return (
+ *
+ * );
+ * }
+ * ```
+ *
+ * @see {@link getDocumentTheme} for the underlying function
+ * @see {@link applyDocumentTheme} to set the theme
+ */
+export function useDocumentTheme(): McpUiTheme {
+ const [theme, setTheme] = useState(getDocumentTheme);
+
+ useEffect(() => {
+ const observer = new MutationObserver(() => {
+ setTheme(getDocumentTheme());
+ });
+
+ observer.observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ["data-theme", "class"],
+ characterData: false,
+ childList: false,
+ subtree: false,
+ });
+
+ return () => observer.disconnect();
+ }, []);
+
+ return theme;
+}
diff --git a/src/styles.ts b/src/styles.ts
index 52ab6a1..4544248 100644
--- a/src/styles.ts
+++ b/src/styles.ts
@@ -1,4 +1,77 @@
-import { McpUiStyles } from "./types";
+import { McpUiStyles, McpUiTheme } from "./types";
+
+/**
+ * Get the current document theme from the root HTML element.
+ *
+ * Reads the theme from the `data-theme` attribute on `document.documentElement`.
+ * Falls back to checking for a `dark` class for compatibility with Tailwind CSS
+ * dark mode conventions.
+ *
+ * @returns The current theme ("light" or "dark")
+ *
+ * @example Check current theme
+ * ```typescript
+ * import { getDocumentTheme } from '@modelcontextprotocol/ext-apps';
+ *
+ * const theme = getDocumentTheme();
+ * console.log(`Current theme: ${theme}`);
+ * ```
+ *
+ * @see {@link applyDocumentTheme} to set the theme
+ * @see {@link McpUiTheme} for the theme type
+ */
+export function getDocumentTheme(): McpUiTheme {
+ const theme = document.documentElement.getAttribute("data-theme");
+
+ if (theme === "dark" || theme === "light") {
+ return theme;
+ }
+
+ // Fallback: check for "dark" class (Tailwind CSS convention)
+ const darkMode = document.documentElement.classList.contains("dark");
+
+ return darkMode ? "dark" : "light";
+}
+
+/**
+ * Apply a theme to the document root element.
+ *
+ * Sets the `data-theme` attribute and CSS `color-scheme` property on
+ * `document.documentElement`. This enables CSS selectors like
+ * `[data-theme="dark"]` and ensures native elements (scrollbars, form controls)
+ * respect the theme.
+ *
+ * @param theme - The theme to apply ("light" or "dark")
+ *
+ * @example Apply theme from host context
+ * ```typescript
+ * import { applyDocumentTheme } from '@modelcontextprotocol/ext-apps';
+ *
+ * app.onhostcontextchanged = (params) => {
+ * if (params.theme) {
+ * applyDocumentTheme(params.theme);
+ * }
+ * };
+ * ```
+ *
+ * @example Use with CSS selectors
+ * ```css
+ * [data-theme="dark"] {
+ * --bg-color: #1a1a1a;
+ * }
+ * [data-theme="light"] {
+ * --bg-color: #ffffff;
+ * }
+ * ```
+ *
+ * @see {@link getDocumentTheme} to read the current theme
+ * @see {@link McpUiTheme} for the theme type
+ */
+export function applyDocumentTheme(theme: McpUiTheme): void {
+ const root = document.documentElement;
+ root.setAttribute("data-theme", theme);
+ root.style.colorScheme = theme;
+}
/**
* Apply host styles as CSS custom properties on an element.