# rapidUI – full documentation > Accessible, themeable React components for the Rapid Development Framework. Built on shadcn/ui and Base UI, installed with the shadcn CLI. ## Setup rapidUI is a shadcn/ui registry. Components are copied into the project as source (`components/ui/*`), not installed as a package. Requires React 19, Tailwind CSS v4 and a `components.json` (run `npx shadcn@latest init` first if it is missing). 1. Apply the Rapid theme (CSS variables, fonts, base styles): `npx shadcn@latest init https://rdf.dev.360online.com/r/styles/rapid.json` 2. Add a component: `npx shadcn@latest add https://rdf.dev.360online.com/r/button.json` 3. Import it: `import { Button } from '@/components/ui/button'` Optional: register the namespace in `components.json` to use short names (`npx shadcn@latest add @rapid/button`): ```json { "registries": { "@rapid": "https://rdf.dev.360online.com/r/{name}.json" } } ``` Rules for agents: - Install with the shadcn CLI instead of writing components by hand; dependencies between components resolve automatically. - Use theme tokens (`bg-primary`, `text-muted-foreground`, `border-border`, …) rather than raw colours. - The theme uses shadcn's CSS variables plus `--success` and `--warning` (with `-foreground`), so any shadcn component or example works unchanged. Use `text-success`, `bg-warning/10` and so on for status colours. Buttons and fields are 40px by default (32px for `sm`), text 14px and badges 12px. - Components are built on Base UI: compose with the `render` prop (e.g. `}>`), there is no `asChild`. Changes from the Radix version: https://rdf.dev.360online.com/docs/base-ui/ --- # Accordion Vertically stacked, collapsible sections built on Base UI Accordion. Install: `npx shadcn@latest add https://rdf.dev.360online.com/r/accordion.json` Import from: `@/components/ui/accordion` npm dependencies: @base-ui/react@^1.8.0, lucide-react@^1.48.0 A vertically stacked set of interactive headings that each reveal a section of content. Built on top of [Base UI Accordion](https://base-ui.com/react/components/accordion), it follows WAI-ARIA design patterns and animates open and closed. ### Features - One expanded section at a time by default, or several with `multiple` - Every open section can be closed again - Height animation on open/close (`animate-accordion-down` / `animate-accordion-up`) - Chevron indicator that switches from down to up when the item is expanded - Items are separated by a bottom border (except the last one) - Content styles for rich text: links are underlined and consecutive paragraphs are spaced - Disabled items - Keyboard navigation and screen reader support - `data-slot` attributes (`accordion`, `accordion-item`, `accordion-trigger`, `accordion-content`) for styling hooks ### Usage ```tsx import { Accordion, AccordionItem, AccordionTrigger, AccordionContent, } from '@/components/ui/accordion' // One section open at a time export function PermitFaq() { return ( Do I need a building permit for a garden shed? Not if it is smaller than 15 m² and lower than 3 metres. How long does it take to get a decision? Most complete applications are decided within 4 weeks. ) } // Several sections open at once export function CaseDetails() { return ( Applicant Anna Lindqvist Property Eken 4:12, Storgatan 14 ) } ``` #### Default A FAQ for a building permit e-service. By default one answer is open at a time, and `defaultValue={['need-permit']}` opens the first one. `value` and `defaultValue` are always arrays. #### Multiple Sections With `multiple` several sections can be open at once, which suits a case summary where the handling officer compares applicant and property details side by side. #### Bordered Wrap the accordion in a border and pad the items with `className` for a card-like list. Triggers can hold an icon next to the label. #### Disabled State Disable an `AccordionItem` for a step that is not available yet, here the offer in a preschool placement application. #### Rich Content Paragraphs and links inside `AccordionContent` get spacing and underline styles automatically, and you can add actions such as a button. ### Props #### Accordion - `multiple` - Whether several items can be open at once (default `false`) - `defaultValue` - The values of the items to open by default (an array, also when only one item can be open) - `value` - The controlled values of the open items (an array) - `onValueChange` - Event handler for when the opened items change, `(value, eventDetails) => void` - `hiddenUntilFound` - Keep closed panels findable with the browser's find-in-page, which opens the matching item - `disabled` - Disables every item - `className` - Additional CSS classes (the root is a full-width flex column) #### AccordionItem - `value` - Unique identifier for the item - `disabled` - Whether the item is disabled - `className` - Additional CSS classes #### AccordionTrigger - `children` - Content to display in the trigger. A chevron icon is appended automatically. - `headingLevel` - The heading level wrapping the trigger: `2`, `3` or `4` (default `3`). Pick the level that follows the heading above the accordion, so the page outline skips no level, for example `2` when it sits directly under the page's H1. - `className` - Additional CSS classes #### AccordionContent - `children` - Content to display when expanded - `className` - Additional CSS classes ### Accessibility The Accordion component follows WAI-ARIA guidelines: - Uses proper ARIA roles (`region`, `button`) - Supports keyboard navigation: - `Space/Enter`: Toggle section - `Tab`: Navigate between sections - `Home/End`: Move to first/last section - Announces state changes to screen readers - Maintains focus management - Provides visual feedback for interaction states ### Best Practices 1. Content Organization: - Group related content together - Use clear, descriptive headers - Keep content concise and focused 2. Visual Hierarchy: - Use consistent spacing - Maintain clear section boundaries - Provide visual feedback for state changes 3. Accessibility: - Write descriptive trigger text - Ensure keyboard navigation - Maintain sufficient touch targets 4. Performance: - Lazy load content when possible - Use appropriate animations - Consider content height changes 5. User Experience: - Allow section collapse when appropriate - Provide smooth transitions - Consider default open states ### Related Components - Tabs - Collapsible ## Source File: components/ui/accordion.tsx ```tsx 'use client' import { Accordion as AccordionPrimitive } from '@base-ui/react/accordion' import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react' import { cn } from '@/lib/utils' function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) { return } function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) { return } interface AccordionTriggerProps extends AccordionPrimitive.Trigger.Props { /** The heading level wrapping the trigger, to fit the page's outline. Defaults to 3. */ headingLevel?: 2 | 3 | 4 } function AccordionTrigger({ className, children, headingLevel = 3, ...props }: Readonly) { const Heading = `h${headingLevel}` as const return ( }> {children} ) } function AccordionContent({ className, children, ...props }: AccordionPrimitive.Panel.Props) { return ( {/* No fixed height here: the open/close keyframes on the panel use --accordion-panel-height, and at rest the content keeps its natural height so it can reflow (zoom, text spacing, content that grows) */}
{children}
) } export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } ``` --- # Alert Inline callout for status messages, with default and destructive variants and an optional action. Install: `npx shadcn@latest add https://rdf.dev.360online.com/r/alert.json` Import from: `@/components/ui/alert` npm dependencies: class-variance-authority@^0.7.1 A versatile alert component for displaying callouts and inline messages. Built with class-variance-authority and styled with Tailwind CSS for consistent visual hierarchy. ### Features - Five variants: `default`, `destructive`, `info`, `success` and `warning` - Optional leading icon: place an `svg` as the first child and the layout switches to a two-column grid - Composable `AlertTitle`, `AlertDescription` and `AlertAction` - `AlertAction` pins a button to the top-right corner - Links inside title and description are underlined automatically - A `role` that follows the variant: `alert` for `destructive`, `status` for the others. Override it with the `role` prop - `data-slot` attributes on every part ### Usage ```tsx import { Alert, AlertAction, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { CalendarClockIcon, WrenchIcon } from 'lucide-react' export function ServiceNotices() { return (
{/* Simple alert */} Planned maintenance on Saturday E-services will be unavailable on 14 March 2026 between 22:00 and 02:00. {/* With action */} Your parking permit expires in 12 days Resident permit for zone C, valid until 10 April 2026.
) } ``` #### Default Alert A neutral notice about planned maintenance of the e-services. #### Variants `default` for neutral notices, `info` for information worth noticing, `success` for confirmations, `warning` for things the user should act on soon, and `destructive` for errors that stop them. #### Status Messages Service messages with the `success`, `info` and `warning` variants. The tinted background and icon colour give each message its tone, but the icon and title carry the meaning, so status never relies on colour alone. ```tsx Water outage on Kungsgatan Kungsgatan 1–27 is without water until about 15:00. ``` #### Roles The `role` decides how a screen reader announces the message: | Role | Default for | Announcement | Use it for | | --- | --- | --- | --- | | `alert` | `destructive` | At once, interrupting what is being read | Errors and urgent messages that appear after an action: a failed submission, a session about to end | | `status` | `default`, `info`, `success`, `warning` | When the screen reader is idle, and only if the alert appears after the page has loaded | Confirmations and updates: a saved draft, a sent application | | `note` or none | – | Never; it is read in its place on the page | Static guidance that is there from the start: processing times, opening hours | ```tsx // Static guidance, never announced … // An urgent warning, announced at once … // No role at all … ``` #### With Action `AlertAction` places a button, such as an action or a dismiss button, in the top-right corner. #### With List Summarise form errors at the top of a form and link each one to its field. #### Compact Title-only or description-only alerts for short, single-line messages. ### Subcomponents - `Alert` - The container; accepts `variant` (`'default' | 'destructive' | 'info' | 'success' | 'warning'`, default `'default'`), `role` (default `'alert'` for `destructive`, `'status'` otherwise) and all `div` attributes - `AlertTitle` - The alert title (renders an `h5`) - `AlertDescription` - The alert description/content - `AlertAction` - Absolutely positioned slot for an action button in the top-right corner ### Variants - `default` - Neutral alert for general information - `destructive` - Alert for errors and critical information - `info` - Primary tint for information the user should notice - `success` - Green tint for confirmations, such as a sent application or a granted permit - `warning` - Amber tint for things that need attention, such as missing documents or a service disruption The status variants keep body text in `foreground` and colour only the border, background and icon, so text contrast stays above 4.5:1 in light and dark mode. ### Accessibility - `destructive` alerts use `role="alert"`, which screen readers announce immediately and interrupt the user for. Keep it for errors and time-sensitive messages - The other variants use `role="status"`: announced politely when the alert appears after the page has loaded, and silent when it is on the page from the start. This covers WCAG 2.2 success criterion 4.1.3 (Status Messages) without interrupting - Pass `role="alert"` for an urgent message in another variant, and `role="note"` for static guidance that should never be announced - Live regions are announced most reliably when the alert is added to a page that is already loaded. For a message shown after navigation, move focus to it or to the page heading instead - Icons are decorative; make sure the title or description conveys the meaning. Status is carried by text and an icon, never by colour alone - Give icon-only buttons in `AlertAction` an `aria-label` ### Best Practices 1. **Choose appropriate variants**: - Use `default` for general notices - Use `info`, `success` and `warning` for status messages - Use `destructive` for errors and critical information 2. **Content guidelines**: - Keep titles concise and descriptive - Provide clear, actionable descriptions - Use icons that reinforce the message type 3. **Layout considerations**: - Place alerts near the content they relate to - Use consistent spacing between multiple alerts ### Common Patterns #### Form Validation ```tsx Fix 2 problems before you send the application ``` #### Success Notification ```tsx Application sent Your case number is 2026-04812. We have sent a confirmation to your email. ``` #### Dismissible Banner ```tsx From 1 June the city library is open until 20:00 on weekdays. ``` ## Source File: components/ui/alert.tsx ```tsx import { cva, type VariantProps } from 'class-variance-authority' import type * as React from 'react' import { cn } from '@/lib/utils' const alertVariants = cva( "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", { variants: { variant: { default: 'bg-background text-foreground *:[svg]:text-foreground', destructive: 'border-destructive-border bg-destructive-subtle text-foreground *:[svg]:text-destructive-subtle-foreground', info: 'border-info-border bg-info-subtle text-foreground *:[svg]:text-info-subtle-foreground', success: 'border-success-border bg-success-subtle text-foreground *:[svg]:text-success-subtle-foreground', warning: 'border-warning-border bg-warning-subtle text-foreground *:[svg]:text-warning-subtle-foreground', }, }, defaultVariants: { variant: 'default', }, }, ) /** * A callout for an inline message. * * The default `role` follows the variant: `destructive` is `alert`, which screen readers announce at once and * interrupt the user for; every other variant is `status`, which is announced politely when the message appears after * the page has loaded and stays quiet when it is there from the start. Pass `role="alert"` for an urgent message in * another variant, or `role="note"` (or `role={undefined}`) for static text that should never be announced. */ function Alert({ className, variant, ...props }: React.ComponentProps<'div'> & VariantProps) { return (
) } function AlertTitle({ className, ...props }: React.ComponentProps<'h5'>) { return (
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground', className, )} {...props} /> ) } function AlertDescription({ className, ...props }: React.ComponentProps<'div'>) { return (
) } function AlertAction({ className, ...props }: React.ComponentProps<'div'>) { return
} export { Alert, AlertTitle, AlertDescription, AlertAction } ``` --- # Alert Dialog Modal confirmation dialog that interrupts the user and expects a response. Install: `npx shadcn@latest add https://rdf.dev.360online.com/r/alert-dialog.json` Import from: `@/components/ui/alert-dialog` Builds on: button npm dependencies: @base-ui/react@^1.8.0 A modal dialog component that interrupts the user with important content and expects a response. Built on top of [Base UI Alert Dialog](https://base-ui.com/react/components/alert-dialog), it follows WAI-ARIA design patterns and provides a fully accessible dialog experience. ### Features - Focus management - Keyboard navigation - Screen reader announcements - Responsive design - Customizable content - Animated transitions - Blurred backdrop overlay - Two sizes: `default` and `sm` (`size` on `AlertDialogContent`) - Optional icon/media slot (`AlertDialogMedia`) - `AlertDialogAction` and `AlertDialogCancel` render as `Button`, accept its `variant` and `size`, and close the dialog when clicked - Render the trigger as any component with the `render` prop, e.g. `render={ ) : null}
) } function BannerTitle({ className, ...props }: React.ComponentProps<'p'>) { return

} function BannerDescription({ className, ...props }: React.ComponentProps<'p'>) { return (

) } // Renders a link by default. Use `render={ {/* With variant and size */} {/* With icons */} {/* Icon-only */} {/* As link */}

) } ``` #### Default Button The default button style with primary color, for the main action on a page. #### All Variants Each variant with the kind of action it suits. #### Disabled Disabled buttons in the footer of an application that isn’t signed yet. Explain nearby why the action isn’t available. #### Sizes Text button sizes, from `xs` to `lg`. #### Icon Sizes Square sizes for icon-only buttons, and a toolbar of ghost icon buttons. Always provide an `aria-label`. #### Row Actions `ghost-destructive` is for a delete action that sits beside other actions. It is as quiet as `ghost` at rest, so it doesn't draw the eye in every row, and turns destructive on hover and keyboard focus. Name each icon button with `aria-label`, including what it acts on. The label and icon carry the meaning, not the red, and a delete that can't be undone should still ask for confirmation, for example in an `AlertDialog`. ```tsx ``` #### With Icons Mark icons with `data-icon="inline-start"` or `data-icon="inline-end"` so the button adjusts its padding. SVGs are sized automatically unless you pass a `size-*` class. #### Loading State There is no built-in loading prop. Compose a spinning icon and disable the button while the action runs. ```tsx ``` #### As Link Use the `render` prop to render the button as another element, such as a link. Set `nativeButton={false}` whenever the rendered element is not a ` ``` #### Form Actions A typical footer in a multi-step e-service: a ghost Back button on the left, and Save draft and Continue on the right. ### Props - `variant` - `'default' | 'outline' | 'secondary' | 'ghost' | 'destructive' | 'ghost-destructive' | 'link'` (default `'default'`) - `size` - `'default' | 'xs' | 'sm' | 'lg' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg'` (default `'default'`) - `render` - `React.ReactElement | (props, state) => React.ReactElement`, the element to render instead of ` // Split button ``` #### Default Actions on a message in the case inbox. Give the group an `aria-label` when its purpose isn’t obvious from the buttons. #### Sizes Buttons keep their own size inside a group; use matching text and icon sizes. #### Vertical `orientation="vertical"` stacks the buttons, here as zoom controls on a property map. #### With separator A split button: the main action plus a dropdown with alternatives, divided by `ButtonGroupSeparator`. #### With text `ButtonGroupText` with `render={