# Nuecrea UI > Accessible UI components for Angular (22+) and Next.js (App Router, React 19+) with the same parts, data attributes and look in both. Styled with Tailwind CSS v4 and design tokens; components are copied into the app by a CLI, so the app owns the code. Set up with `npx nuecrea-ui init`, then add components with `npx nuecrea-ui add ` (e.g. `dialog`). `nuecrea.json` in the app says which framework it uses and where the components live. Agent Skills: `npx nuecrea-ui skills install`. --- # Accordion (React / Next.js) Stacked sections that expand and collapse; one open at a time unless multiple. Panel height animates via CSS. Follows the [WAI-ARIA pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/). Add it: `npx nuecrea-ui add accordion` ## Usage ```tsx import * as Accordion from '@/components/ui/accordion'; const items = [ { value: 'shipping', title: 'How long does shipping take?', body: 'Orders ship within 2 business days.', }, { value: 'returns', title: 'Can I return an item?', body: 'Yes, within 30 days of delivery.' }, { value: 'gift', title: 'Do you offer gift wrapping?', body: 'Not yet.', disabled: true }, { value: 'support', title: 'How do I contact support?', body: 'Email help@example.com.' }, ]; export default function AccordionStory() { return (
{items.map((item) => ( {item.title} {item.body} ))} Locked section Hidden content.
); } ``` ## Parts ### Groups items; owns which are open. Renders `
`. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | `unknown[]` | | Controlled open item values. | | `defaultValue` | `unknown[]` | | Initially open item values. | | `multiple` | `boolean` | `false` | Allow several open items. | | `disabled` | `boolean` | `false` | Disable every item. | | `keepMounted` | `boolean` | `false` | Keep closed panels in the DOM (hidden). | | Event | Payload | Description | | --- | --- | --- | | `onValueChange` | `unknown[]` | Fired when items open or close. Angular: the `value` model's change event. | | Data attribute | Present when | | --- | --- | | `data-orientation` | always: vertical | | `data-disabled` | the accordion is disabled | ### One section. Renders `
`. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | `unknown` | | Identifies the item. Generated when unset. | | `disabled` | `boolean` | `false` | Cannot be toggled. | | Event | Payload | Description | | --- | --- | --- | | `onOpenChange` | `boolean` | Fired when this item opens or closes. | | Data attribute | Present when | | --- | --- | | `data-orientation` | always: vertical | | `data-open` | the item is open | | `data-closed` | the item is closed | | `data-hidden` | the item's panel is hidden | | `data-disabled` | the item (or whole accordion) is disabled | | `data-index` | always: the item's index | ### Heading wrapping the trigger. Renders `

`. | Data attribute | Present when | | --- | --- | | `data-orientation` | always: vertical | | `data-open` | the item is open | | `data-closed` | the item is closed | | `data-hidden` | the item's panel is hidden | | `data-disabled` | the item (or whole accordion) is disabled | | `data-index` | always: the item's index | ### Toggles the panel. A plain button in the tab order; the styled version appends a chevron. Renders `

{{ item.body }}
}

Hidden content.
`, }) export class AccordionStory { protected readonly items = [ { value: 'shipping', title: 'How long does shipping take?', body: 'Orders ship within 2 business days.', }, { value: 'returns', title: 'Can I return an item?', body: 'Yes, within 30 days of delivery.' }, { value: 'gift', title: 'Do you offer gift wrapping?', body: 'Not yet.', disabled: true }, { value: 'support', title: 'How do I contact support?', body: 'Email help@example.com.' }, ]; } ``` ## Parts ### libAccordionRoot Groups items; owns which are open. Renders `
`. | Input | Type | Default | Description | | --- | --- | --- | --- | | `[value]` | `unknown[]` | | Controlled open item values. | | `[defaultValue]` | `unknown[]` | | Initially open item values. | | `[multiple]` | `boolean` | `false` | Allow several open items. | | `[disabled]` | `boolean` | `false` | Disable every item. | | `[keepMounted]` | `boolean` | `false` | Keep closed panels in the DOM (hidden). | | Output | Payload | Description | | --- | --- | --- | | `(valueChange)` | `unknown[]` | Fired when items open or close. Angular: the `value` model's change event. | | Data attribute | Present when | | --- | --- | | `data-orientation` | always: vertical | | `data-disabled` | the accordion is disabled | ### libAccordionItem One section. Renders `
`. | Input | Type | Default | Description | | --- | --- | --- | --- | | `[value]` | `unknown` | | Identifies the item. Generated when unset. | | `[disabled]` | `boolean` | `false` | Cannot be toggled. | | Output | Payload | Description | | --- | --- | --- | | `(openChange)` | `boolean` | Fired when this item opens or closes. | | Data attribute | Present when | | --- | --- | | `data-orientation` | always: vertical | | `data-open` | the item is open | | `data-closed` | the item is closed | | `data-hidden` | the item's panel is hidden | | `data-disabled` | the item (or whole accordion) is disabled | | `data-index` | always: the item's index | ### libAccordionHeader Heading wrapping the trigger. Renders `

`. | Data attribute | Present when | | --- | --- | | `data-orientation` | always: vertical | | `data-open` | the item is open | | `data-closed` | the item is closed | | `data-hidden` | the item's panel is hidden | | `data-disabled` | the item (or whole accordion) is disabled | | `data-index` | always: the item's index | ### libAccordionTrigger Toggles the panel. A plain button in the tab order; the styled version appends a chevron. Renders ` ))}

))}
); } ``` ## Parts ### }
}
`, }) export class ButtonStory { protected readonly variants = [ 'default', 'secondary', 'outline', 'ghost', 'destructive', 'link', ] as const; protected readonly sizes = ['sm', 'md', 'lg'] as const; } ``` ## Parts ### libButton The button element. Renders ` ); } ``` ## Parts ### The group. Its direct children are joined, so put Buttons (or Menu/Popover triggers) straight inside. Renders `
` with role `group`. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `orientation` | `'horizontal' \| 'vertical'` | `"horizontal"` | Lays the buttons out in a row or a column. | | Data attribute | Present when | | --- | --- | | `data-orientation` | always: 'horizontal' or 'vertical' | --- # Button Group (Angular) Joins related Buttons into one visual unit with shared borders. A div with role=group: give it an aria-label. Every button stays its own tab stop; for arrow-key navigation between them use a toolbar instead. Add it: `npx nuecrea-ui add button-group` ## Usage ```ts import { Component } from '@angular/core'; import { Button } from './ui/button'; import { ButtonGroup } from './ui/button-group'; @Component({ imports: [Button, ButtonGroup], template: `
`, }) export class ButtonGroupStory {} ``` ## Parts ### libButtonGroup The group. Its direct children are joined, so put Buttons (or Menu/Popover triggers) straight inside. Renders `
` with role `group`. | Input | Type | Default | Description | | --- | --- | --- | --- | | `[orientation]` | `'horizontal' \| 'vertical'` | `"horizontal"` | Lays the buttons out in a row or a column. | | Data attribute | Present when | | --- | --- | | `data-orientation` | always: 'horizontal' or 'vertical' | --- # Card (React / Next.js) A bordered surface grouping related content, with optional header, content and footer areas. Layout only: no role or behaviour. Give Title a heading element (React `render={

}`, Angular `

`) when the card starts a section. Add it: `npx nuecrea-ui add card` ## Usage ```tsx import { Button } from '@/components/ui/button'; import * as Card from '@/components/ui/card'; export default function CardStory() { return (
Upgrade to Pro Unlimited projects and priority support.

$12 per member, billed monthly.

A card with content only.

); } ``` ## Parts ### The card surface. Stacks its parts with a gap. Renders `
`. ### Holds the Title and Description. Renders `
`. ### The card's title. A
by default; render it as a heading of the level the page needs. Renders `
`. ### Supporting text under the title. Renders `
`. ### The card's main content. Renders `
`. ### A row for actions, aligned to the bottom of the card. Renders `
`. --- # Card (Angular) A bordered surface grouping related content, with optional header, content and footer areas. Layout only: no role or behaviour. Give Title a heading element (React `render={

}`, Angular `

`) when the card starts a section. Add it: `npx nuecrea-ui add card` ## Usage ```ts import { Component } from '@angular/core'; import { Button } from './ui/button'; import { Card } from './ui/card'; @Component({ imports: [Button, Card], template: `
Upgrade to Pro
Unlimited projects and priority support.

$12 per member, billed monthly.

A card with content only.

`, }) export class CardStory {} ``` ## Parts ### libCardRoot The card surface. Stacks its parts with a gap. Renders `
`. ### libCardHeader Holds the Title and Description. Renders `
`. ### libCardTitle The card's title. A
by default; render it as a heading of the level the page needs. Renders `
`. ### libCardDescription Supporting text under the title. Renders `
`. ### libCardContent The card's main content. Renders `
`. ### libCardFooter A row for actions, aligned to the bottom of the card. Renders `
`. --- # Checkbox (React / Next.js) A checkbox on a with a hidden native input beside it for forms. Follows the [WAI-ARIA pattern](https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/). Add it: `npx nuecrea-ui add checkbox` ## Usage ```tsx import * as Checkbox from '@/components/ui/checkbox'; import * as Field from '@/components/ui/field'; const label = 'flex items-center gap-2 text-sm'; export default function CheckboxStory() { return (
Accept the terms You must accept the terms.
); } ``` ## Parts ### The checkbox. Labelled by a wrapping

{{ label() }}

You're all caught up.

`, }) class PopoverExample { readonly label = input.required(); readonly side = input('bottom'); readonly align = input('center'); readonly arrowPadding = input(5); readonly disabled = input(false); } @Component({ imports: [PopoverExample], host: { class: 'contents' }, template: `
`, }) export class PopoverStory {} ``` ## Parts ### libPopoverRoot Owns the open state. Renders nothing. Renders nothing: put it on ``. | Input | Type | Default | Description | | --- | --- | --- | --- | | `[open]` | `boolean` | | Controlled open state. | | `[defaultOpen]` | `boolean` | `false` | Initial open state. | | `[modal]` | `boolean \| 'trap-focus'` | `false` | true: trap focus, inert page, lock scroll. | | Output | Payload | Description | | --- | --- | --- | | `(openChange)` | `boolean` | Fired when it opens or closes. Angular: the `open` model's change event. | | `(openChangeComplete)` | `boolean` | Fired after the animation finishes. | ### libPopoverTrigger Toggles the popover. Renders `
Popular
Others
Size
Region
`, }) export class SelectStory { protected readonly frameworks = { react: 'React', angular: 'Angular', vue: 'Vue', svelte: 'Svelte', solid: 'Solid', }; protected readonly sizes = { sm: 'Small', md: 'Medium', lg: 'Large' }; } ``` ## Parts ### libSelectRoot Owns value and open state; submits through a hidden input. Renders nothing. Renders nothing: put it on ``. | Input | Type | Default | Description | | --- | --- | --- | --- | | `[value]` | `unknown` | | Controlled value. | | `[defaultValue]` | `unknown` | | Initial value. | | `[items]` | `Record \| { label: string; value: unknown }[]` | | Labels for values, so the trigger can show a label before the list has opened. | | `[name]` | `string` | | Form field name of the hidden input. | | `[disabled]` | `boolean` | `false` | Disabled. | | `[readOnly]` | `boolean` | `false` | Can't change (aria-readonly, data-readonly). | | `[required]` | `boolean` | `false` | Required (aria-required). | | `[modal]` | `boolean` | `true` | Lock page scroll while open. | | Output | Payload | Description | | --- | --- | --- | | `(valueChange)` | `unknown` | Angular: the `value` model's change event; also a ControlValueAccessor. | | `(openChange)` | `boolean` | Angular: the `open` model's change event. | ### libSelectLabel Labels the trigger. Renders `
`. ### libSelectTrigger role=combobox. Arrows/Enter/Space open; typing selects without opening. Renders `