# AhroweProvider

**When to use:** The one wrapper an app needs, at its root: it applies the theme, sets default props for every component, shows toasts and renders the element that Modal, Tooltip, Popover, Menu and Toast portal into. Nest another one for a section with its own theme or defaults.

**Keywords:** setup, getting started, install, bootstrap, app shell, dark mode, notifications

**Import:** `import { AhroweProvider } from '@ahrowe/ui'`  
**Types:** `import type { AhroweProviderProps } from '@ahrowe/ui'`

```tsx
import '@ahrowe/ui/style.css';
import { AhroweProvider, defaultTheme, lightTheme, useTheme } from '@ahrowe/ui';

// Keep `themes` stable, here at module scope: a new array on every render reads as a theme change.
const THEMES = [defaultTheme, lightTheme];

function Root() {
  const { currentThemeId } = useTheme();

  return (
    <AhroweProvider
      themes={THEMES}
      currentThemeId={currentThemeId}
      defaultProps={{ Input: { alwaysFloatLabel: true } }}
      toast={{ position: 'bottom-right', duration: 3000 }}
    >
      <App />
    </AhroweProvider>
  );
}
```

Every prop is optional. `<AhroweProvider><App /></AhroweProvider>` applies `defaultTheme` and shows toasts with their built-in settings.

**Key props:**

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `themes` | `Theme[]` | `[defaultTheme]` | The themes to choose from. See [ThemeProvider.md](ThemeProvider.md) |
| `currentThemeId` | `string` | the first theme without a `baseThemeId` | The `id` of the theme to apply |
| `defaultProps` | `ComponentDefaults` | | Default props per component. See [ConfigProvider.md](ConfigProvider.md) |
| `presentation` | `Presentation` | | How every sheet-capable component presents. See [ConfigProvider.md](ConfigProvider.md) |
| `navigate` | `(path: string) => void` | | The app's router, for the links components render. Usually set on a `ConfigProvider` inside the router instead, see [ConfigProvider.md](ConfigProvider.md) |
| `locale` | `string` | the browser's | BCP 47 tag (`'de-AT'`) for the dates, week start and sort order components produce. See [ConfigProvider.md](ConfigProvider.md) |
| `toast` | `ToastContextConfig` | | Settings for every toast `showToast` shows. See [Toast.md](Toast.md) |
| `scrollbars` | `boolean` | `true` | Styles every scrollbar inside the app in the theme's colours. See **Scrollbars** |

## What it renders

The theme's wrapper `div`. Inside it, in a `display: contents` element that styles the scrollbars (unless `scrollbars={false}`), come an empty `<template>`, your app and, after it, the element everything portalled renders into. That is why no `<div id="bodyEnd" />` is needed. Portalled panels stay inside the theme's wrapper and come after the app, so they paint above it. Each one gets the font and colours of the theme it was written under, a nested one included.

On the server, and while hydrating, nothing is portalled: the server has nowhere to put it. Panels appear on the render right after hydration.

## Nesting

A nested `AhroweProvider` applies its `themes`, `currentThemeId`, `defaultProps`, `presentation`, `navigate` and `locale` to its section. Its `defaultProps` merge with the outer ones per component, the same as nested `ConfigProvider`s. Toasts, scrollbars and the portal element stay with the outermost provider, so a nested `toast` or `scrollbars` is ignored, with a warning.

Only a provider inside another `AhroweProvider` counts as nested. Put the outer one at the root first: one placed around a section of an app that has none renders the portal element inside that section, where an `overflow: hidden` or a `transform` around it clips every panel.

`ThemeProvider` and `ConfigProvider` still work on their own, for a section that needs only one of the two.

## Scrollbars

Every scrollbar inside the provider, portalled panels included, is thin, with a rounded thumb in the theme's `--background-accent-light`. The page's own scrollbar, when the window itself scrolls, gets the same thumb colour: it belongs to `<html>`, outside the provider, so the provider hands the colour up in `--ahrowe-page-scrollbar-thumb`. A browser without `scrollbar-color` keeps its own page scrollbar.

None of this outweighs a rule of yours. Every one of these rules has zero specificity, so any scrollbar rule on an element, on `<html>` or on `:root` wins. `scrollbars={false}` turns all of it off; `ScrollbarProvider` then styles one region at a time.

## Migrating from separate providers

```tsx
// Before
<ThemeProvider themes={THEMES} currentThemeId={currentThemeId}>
  <ConfigProvider defaultProps={defaults}>
    <ToastProvider position="bottom-right">
      <App />
    </ToastProvider>
  </ConfigProvider>
  <div id="bodyEnd" />
</ThemeProvider>

// After
<AhroweProvider
  themes={THEMES}
  currentThemeId={currentThemeId}
  defaultProps={defaults}
  toast={{ position: 'bottom-right' }}
>
  <App />
</AhroweProvider>
```

Delete the `<div id="bodyEnd" />`, including one in `index.html`: inside `AhroweProvider` nothing renders into it. Delete a `ScrollbarProvider` around the app too, or, if the app had none, pass `scrollbars={false}` to keep the browser's scrollbars. `ToastProvider` was removed in 0.41, and its props are the keys of `toast`.
