# Dynamic Control
URL: /concepts/additional-context/dynamic-control
Context helpers can be dynamically managed using the `useTamboContextHelpers` hook.
## Available Functions
```tsx
import { useTamboContextHelpers } from "@tambo-ai/react";
const {
getContextHelpers, // Get the current map of helpers
addContextHelper, // Add or replace a helper
removeContextHelper, // Remove a helper
} = useTamboContextHelpers();
```
**Note:**
* Helpers are just functions; to “disable” a helper, replace it with a function that returns null.
* You can also configure helpers declaratively using `TamboContextHelpersProvider`; both approaches write to the same global registry.
## Add/Replace Helpers at Runtime
Useful when context depends on user actions or app state:
```tsx
function ProjectContextController({ projectId }: { projectId: string }) {
const { addContextHelper, removeContextHelper } = useTamboContextHelpers();
useEffect(() => {
if (!projectId) return;
addContextHelper("currentProject", async () => ({
projectId,
projectName: await getProjectName(projectId),
projectData: await getProjectData(projectId),
}));
return () => {
removeContextHelper("currentProject");
};
}, [projectId]);
return null;
}
```
## Removing Helpers
```tsx
const { removeContextHelper } = useTamboContextHelpers();
// User logs out
removeContextHelper("session");
```
## Building a Settings UI
`getContextHelpers` returns the current map of helper functions keyed by name.
You can build toggles by swapping in a real function or a no-op function that returns null:
```tsx
function ContextSettings() {
const { getContextHelpers, addContextHelper } = useTamboContextHelpers();
const helpers = getContextHelpers();
return (
Privacy Settings
{Object.keys(helpers).map((key) => (
{key}
))}
);
}
```
## Register helpers from multiple pages using the Provider
You can also register helpers declaratively at the page or layout level with `TamboContextHelpersProvider`. Helpers are registered when the provider mounts and are active only while that provider remains mounted (for example, while you’re on that page/layout). If the same key is registered multiple times at different times, the most recently mounted provider takes effect for as long as it’s mounted.
**App layout (optional global helpers):**
```tsx title="app/layout.tsx"
import { TamboProvider, TamboContextHelpersProvider } from "@tambo-ai/react";
import { currentTimeContextHelper } from "@tambo-ai/react";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
);
}
```
**Page A (adds a page-specific helper):**
```tsx title="app/dashboard/page.tsx"
"use client";
import { TamboContextHelpersProvider } from "@tambo-ai/react";
import { currentPageContextHelper } from "@tambo-ai/react";
import { MessageThreadFull } from "@/components/tambo/message-thread-full";
export default function DashboardPage() {
return (
);
}
```
**Page B (adds a different helper or overrides a key):**
```tsx title="app/settings/page.tsx"
"use client";
import { TamboContextHelpersProvider } from "@tambo-ai/react";
const getUserSettingsContext = async () => ({
theme: "dark",
notifications: true,
});
export default function SettingsPage() {
return (
({ url: "/settings", title: "Settings" }),
}}
>
{/* Components that send messages */}
);
}
```
* If you only want a helper active while a page is mounted, register it in that page’s provider (like above), or use the hook with add/remove in a `useEffect` with cleanup.
* Consider namespacing keys if multiple parts of the app might register the same context (e.g., `dashboard:userPage`).
## What Happens Behind the Scenes
When you send a message, Tambo automatically:
1. Calls all configured helper functions.
2. Filters out null/undefined results.
3. Merges the results with any manual `additionalContext`.
4. Sends everything with the message.