Set up Bridge UI in a Next.js App Router project.
Bridge UI React works with Next.js using a client provider in the App Router.
Use the framework selector in the site header to switch between React and Vue.
Install packages
Packages are published on npm as 0.0.3.
Bridge UI Vue targets Vue apps. For a Vue SSR stack, use the Nuxt guide instead.
bun add @bridge-ui/[email protected]pnpm add @bridge-ui/[email protected]yarn add @bridge-ui/[email protected]npm install @bridge-ui/[email protected]Providers
Interactive Bridge UI components and imperative actions need a client boundary. Create a providers component and wrap your root layout:
See the Nuxt guide for Vue setup.
app/providers.tsx:
"use client";
import { BridgeUIProvider } from "@bridge-ui/react";
import { BridgeUIHosts } from "@bridge-ui/react/Actions";
import type { PropsWithChildren } from "react";
export function Providers({ children }: PropsWithChildren) {
return (
<BridgeUIProvider global={{}} components={{}}>
<BridgeUIHosts
modal={{ modal: { transition: "fade" } }}
dialog={{ modal: { transition: "fade" } }}
snackbar={{ max: 3, timeout: 5000, position: "bottom-center" }}
>
{children}
</BridgeUIHosts>
</BridgeUIProvider>
);
}
app/layout.tsx:
import { Providers } from "./providers";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
BridgeUIHosts enables imperative actions ( useModalAction, useDialogAction, useSnackbarAction) from any client component under the provider.
Using components
Import Bridge UI components from client components (or pages marked with "use client"):
See the Nuxt guide.
"use client";
import { Button } from "@bridge-ui/react/Components/Button";
export function Example() {
return <Button>Save</Button>;
}
Select async data
The Select component accepts an asyncData object with search and resolve callbacks. Call your own JSON API with axios (Route Handlers, external API, etc.).
Client helper
Create lib/asyncSelect.ts:
import type { SelectAsyncData, SelectValue } from "@bridge-ui/core";
import axios from "axios";
export function asyncSelect(options: { url: string }): SelectAsyncData {
const { url } = options;
return {
limit: 20,
resolve: async (values: SelectValue[]) => {
const { data } = await axios.get(url, {
params: { ids: values },
headers: { Accept: "application/json" },
});
return data;
},
search: async (query) => {
const params: Record<string, string> = {};
if (query) params.search = query;
const { data } = await axios.get(url, {
params,
headers: { Accept: "application/json" },
});
return data;
},
};
}
Your endpoint should return { label, value, description } objects and accept:
| Param | Purpose |
|---|---|
| search | Filter options while the user types |
| ids | Resolve labels for already-selected values |
Usage in a page
See the Nuxt guide.
"use client";
import { useState } from "react";
import { asyncSelect } from "@/examples/core/integrations/asyncSelect";
import { Select } from "@bridge-ui/react/Components/Select";
export function UserSelect() {
const [userId, setUserId] = useState<null | number | string>(null);
return (
<Select
label="User"
value={userId}
onChange={setUserId}
placeholder="Type to search users..."
asyncData={asyncSelect({ url: "/api/examples/users" })}
/>
);
}
asyncData implies searchable. Selected values are resolved through the same endpoint with ids when the page loads or when chips need labels.
Next steps
- useModalAction — imperative modals
- useDialogAction — confirm-style dialogs
- useSnackbarAction — toast notifications