App setup
OuroProvider
Optional app-level provider that routes internal hrefs through your router's link and groups tooltips: once one Tooltip shows, its neighbours open instantly instead of each waiting its own delay. Ouro UI components work without it: they honor reduced motion themselves, in CSS (motion-reduce: variants and prefers-reduced-motion queries), and need no animation library. If your app animates with Motion, wrap it in <MotionConfig reducedMotion="user"> for the same behavior.
import { OuroProvider } from "@/lib/ouro/ouro-provider";Example
// React Router. app/components/ouro-router-link.tsx:
import type { ComponentProps } from "react";
import { Link } from "react-router";
import type { OuroLinkComponent } from "@/lib/ouro/use-ouro";
export function OuroRouterLink({ href, ...props }: ComponentProps<OuroLinkComponent>) {
return <Link to={href} {...props} />;
}
// app/root.tsx:
import { Outlet } from "react-router";
import { OuroProvider } from "@/lib/ouro/ouro-provider";
import { OuroRouterLink } from "@/components/ouro-router-link";
export default function App() {
return (
<OuroProvider linkComponent={OuroRouterLink}>
<Outlet />
</OuroProvider>
);
}
// Next.js App Router. app/providers.tsx:
"use client";
import Link from "next/link";
import type { ReactNode } from "react";
import { OuroProvider } from "@/lib/ouro/ouro-provider";
export function Providers({ children }: { children: ReactNode }) {
return <OuroProvider linkComponent={Link}>{children}</OuroProvider>;
}
// app/layout.tsx, a Server Component:
import type { ReactNode } from "react";
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Usage
It installs with every component that renders links (Button, Link, Card, Item, Table and the navigation components) and with Tooltip. An app with none of those adds it by name, lib-ouro-provider, at the release tag of your other components (the README's Next.js steps show the command). Type a custom adapter with ComponentProps<OuroLinkComponent> so it always compiles, including under exactOptionalPropertyTypes.
Every Ouro UI link takes href: Link, Button, Card, Item and Table rows. An internal href (a path) renders through linkComponent; an absolute URL (https:, mailto:) always renders a plain <a>. Without a provider, or without linkComponent, internal links are plain <a> elements too, so they work but load the page.
React Router's Link takes to, so it needs the adapter in the example, which maps href to to. Wrap the app once, in the root route.
In Next.js, next/link's Link takes href and needs no adapter, but a Server Component can't pass Link, a function, to a client component: render the provider from a client file, app/providers.tsx in the example, and wrap the app in it from app/layout.tsx, which stays a Server Component.
Props
Type: OuroProviderProps.
children(required)- Type:
ReactNode - Your app, or the part of it that uses Ouro UI.
linkComponent- Type:
OuroLinkComponent - Renders internal
hrefs, for example an adapter around a router'sLink. portalContainer- Type:
HTMLElement | RefObject<HTMLElement | null> | null - The element floating popups render into: the lists of
SelectandCombobox, andMenu,Popover,DatePicker,Tooltip,HoverCardandNavigationMenu. Unset, they render at the end of<body>, outside every landmark, where screen reader users who move by landmark miss them. Pass an element, or a ref to one, inside<main>that does not clip what it holds (nooverflowother thanvisible) and is not inside an element with atransform,filterorcontain, which would hold the phone sheets'position: fixed. Render it last in<main>, after the content, so popups stack over the page; a ref works even when the element comes after a popup that is open at once. A provider inside another keeps the outer one's container when it sets none, andnullgives popups Base UI's place again: wrap the content of a dialog that is not Ouro UI's in<OuroProvider portalContainer={null}>so its popups open inside it. Dialogs, sheets and toasts stay at the end of<body>: a dialog is announced when it opens, and the toasts are a landmark of their own.
Types
OuroLinkComponent
A component that renders an internal link, such as a router's Link.
type OuroLinkComponent = ComponentType<
AnchorHTMLAttributes<HTMLAnchorElement> & { href: string; ref?: Ref<HTMLAnchorElement> }
>;