---
title: "Moving Raíz, Agenda and Account"
description: "What changes for Arbol's three dashboards when they move from their own components/ui folders onto @arbol-ai/ui."
---

> Documentation Index
> Fetch the complete documentation index at: https://epidermis.getarbol.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Moving Raíz, Agenda and Account

The library started as the `components/ui` folders of Arbol's three dashboards. Most components keep the
apps' names and props, so moving a screen is usually changing an import from `~/components/ui/…` to
`@arbol-ai/ui`. This page lists what differs.

## Setup, once per app

1. `bun add @arbol-ai/ui` (React Aria, React and Tailwind are already there).
2. In the entry stylesheet, after Tailwind: `@import '@arbol-ai/ui/theme.css';`. Keep the app's own
   `fonts.css` (the theme names Arbol Sans; it never ships font files). The theme does **not** ship the
   apps' global `* { min-width: 0 }` or the unlayered `h1, h2 { font-family: Arbolito }` rule: keep them in
   the app while its own screens depend on them.
3. Render `RouterUIProvider` from `@arbol-ai/ui/router` at the root (it is `UIProvider` wired to TanStack
   Router: `navigate({ href })`, and base paths only for app paths, so `tel:` and `wa.me` links stay intact),
   with the locale:
   - Raíz and Account (Paraglide): `locale={getLocale() === 'es' ? 'es-CO' : 'en-US'}`.
   - Agenda (Spanish only): `locale="es-CO"`. Agenda had no `I18nProvider`, so React Aria's own strings
     (search clear button, drop zone…) followed the browser's language; this fixes it.
4. Mount `<Toaster />` once, inside `UIProvider`, to replace Raíz's sonner `Toaster`.

## Renamed props and changed defaults

| Component                                  | Before (app)                                         | Now                                                                                                                                                                |
| ------------------------------------------ | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Badge`                                    | `variant="success"`, `"destructive-soft"`…           | `tone` (`neutral`, `brand`, `success`, `warning`, `danger`, `info`) and `variant` (`soft`, `outline`); `variant="outline"` still works. JSDoc maps every old name. |
| `Tooltip` (Raíz)                           | `Tooltip` + `TooltipContent`                         | `TooltipTrigger` + `Tooltip` (React Aria's names).                                                                                                                 |
| `SaveBar`                                  | `dirty`, `busy`, `label`                             | `isDirty`, `isPending`, `saveLabel`.                                                                                                                               |
| `Notice`                                   | default tone `success`                               | default tone `info`: pass `tone="success"` where a bare `<Notice>` meant success.                                                                                  |
| `ErrorState`                               | heading `h1`                                         | heading `h2` by default; pass `level={1}` when it is the page.                                                                                                     |
| `Select` (Raíz)                            | `value: string`, `onValueChange`                     | React Aria's `value` / `onChange`; label, description and error built in.                                                                                          |
| `PhoneField` (Raíz `PhoneInput`)           | `onValueChange`, `disabled`, `invalid`, `emptyLabel` | `onChange`, `isDisabled`, `isInvalid`; the empty text is a library string.                                                                                         |
| `CursorPagination` (Raíz `ListPagination`) | `onPrev`                                             | `onPrevious`.                                                                                                                                                      |
| `FilterToggle` (Agenda `InactiveFilter`)   | `selected`                                           | `isSelected`.                                                                                                                                                      |
| `UnsavedChanges` (Agenda)                  | imported TanStack Router                             | `<UnsavedChangesDialog {...useUnsavedChangesBlocker(isDirty)} />` from `@arbol-ai/ui/router`.                                                                      |
| `RowMenu`                                  | navigated with `useNavigate`                         | uses `href`, routed by `UIProvider navigate`.                                                                                                                      |
| `Overlay`                                  | `onClose` after a 200 ms timer                       | same API; `onClose` fires after the exit animation ends. Open it from a button with `OverlayTrigger`, not React Aria's `DialogTrigger`.                            |
| `ColorSwatchPicker` (Agenda `ColorPicker`) | oklch palette                                        | pass the palette as hex (`#rrggbb`), `rgb()` or `hsl()`.                                                                                                           |
| `Sheet` (Raíz)                             | non-modal                                            | always modal; the assistant side panel stays app layout.                                                                                                           |
| `ConfirmationDialog` (Raíz, two of them)   | `labels` object, fixed DOM ids                       | one `ConfirmDialog` with plain props and an optional type-to-confirm value.                                                                                        |
| Toasts (Raíz, sonner)                      | `toast.error(message)`                               | the same call shape from `@arbol-ai/ui`.                                                                                                                           |

## Fixed on the way

- White text on the old destructive red (3.8:1) and on the 90%-opacity primary hover failed WCAG AA; both
  now pass.
- Account's `SearchInput` ignored a controlled value on the first render; Agenda's could run a stale search.
- Account's `SettingToggleCard` nested a `<label>` in a `<label>`; Raíz's `EditableTitle` rendered
  `<button><h1>`.
- Raíz's breadcrumbs announced "breadcrumb" in English; DataTable rows had no keyboard path; nav landmarks had
  no names.
- Agenda's pick list built plurals by concatenation ("1 seleccionado/s").

Source: https://epidermis.getarbol.com/guides/migration/index.mdx
