--- url: /components/avatar.md --- # Avatar Use avatars to give users and entities a recognizable visual identity throughout your application. They display a profile image when available and gracefully fall back to generated initials, so every user always has a face -- even before they upload a photo. ```ts import { CoarAvatar } from '@cocoar/vue-ui'; ``` ## Basic Usage Pass a `name` and the avatar automatically extracts and displays initials. Ideal for user lists, comment threads, and anywhere you need a quick visual identifier. ## With Image Provide a `src` URL to show a profile photo. If the image fails to load, the avatar seamlessly reverts to initials so the layout never breaks. ## Sizes Six sizes let you match the avatar to its context -- use `xs` in dense tables or chat lists, and `xxl` for prominent profile headers. ## Shapes Choose between circle (the default, great for people) and square (useful for teams, organizations, or app icons). ## Avatar Group Stack avatars with negative margins to show team members or participants at a glance. Add a "+N" overflow indicator when the list is too long to display in full. ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `name` | `string` | `''` | User's name (used for initials fallback) | | `src` | `string` | `undefined` | Image URL | | `size` | `'xs' \| 's' \| 'm' \| 'l' \| 'xl' \| 'xxl'` | `'m'` | Avatar size | | `shape` | `'circle' \| 'square'` | `'circle'` | Avatar shape | | `initials` | `string` | `''` | Custom initials override | | `clickable` | `boolean` | `false` | Make avatar interactive (button role) | ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.avatar.avatar` | `'Avatar'` | `aria-label` and `alt` text fallback when no `name` prop is set | --- --- url: /components/badge.md --- # Badge Badges draw attention to counts, statuses, or short labels. Attach them to icons, avatars, or buttons to surface information that needs a quick glance -- like unread messages, plan tiers, or live/offline indicators. ```ts import { CoarBadge } from '@cocoar/vue-ui'; ``` ## Variants Six semantic variants let you match the badge to its meaning -- use `success` for positive states, `error` for alerts, and so on. ## Sizes Five sizes from tiny `xs` (great for inline status) to bold `xl` (ideal for dashboard counters). ## Text Content Badges aren't limited to numbers. Use short text labels like "New", "Beta", or "Pro" to tag features and content. ## Max Value Set a `max` to cap large numbers gracefully. Perfect for notification counts where "99+" is more useful than "1,247". ## Dot Mode When you only need to signal presence or status without a specific value, `dot` mode provides a minimal, color-coded indicator. ## Pulse Animation Add a pulse animation to catch the user's eye for time-sensitive updates like new notifications or live events. ## Bordered The `bordered` prop adds a ring that prevents the badge from visually merging into its parent. Especially useful when badges sit on top of avatars or colored backgrounds. ## Interactive Demo See badges in action -- increment and reset a notification counter to observe live updates and max-capping behavior. ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `content` | `string \| number` | `''` | Badge content (text or number) | | `variant` | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'error' \| 'info'` | `'primary'` | Badge color variant | | `size` | `'xs' \| 's' \| 'm' \| 'l' \| 'xl'` | `'m'` | Badge size | | `dot` | `boolean` | `false` | Show as a small dot with no content | | `max` | `number` | `null` | Cap numeric content (e.g. 100 becomes "99+") | | `pulse` | `boolean` | `false` | Add pulse animation | | `bordered` | `boolean` | `false` | Add white border ring | ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.badge.notificationIndicator` | `'Notification indicator'` | `aria-label` for dot badges (when no `content` value is set) | --- --- url: /components/breadcrumb.md --- # Breadcrumb Show users exactly where they are within a page hierarchy and give them a quick path back to any parent level. Breadcrumbs are especially valuable in applications with deep navigation structures, where the sidebar alone does not make the current location obvious. ```ts import { CoarBreadcrumb, CoarBreadcrumbItem } from '@cocoar/vue-ui'; ``` ## Basic Usage Wrap each level in a `CoarBreadcrumbItem`. Parent levels are rendered as links; the last item is marked `active` to indicate the current page. Separators between items are handled automatically. ## Deep Hierarchy Breadcrumbs scale naturally for deeply nested content. Even a five-level trail remains compact and readable, giving users confidence about their location. ## App Navigation Here are several breadcrumb paths you might encounter in a real application -- from a simple two-level dashboard path to a four-level project issue drill-down. ## Accessibility ### Keyboard Navigation | Key | Action | |-----|--------| | `Tab` | Move between breadcrumb links | | `Enter` | Activate the focused link | | `Shift + Tab` | Move focus backward | ## API ### CoarBreadcrumb Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `separator` | `string` | `'/'` | Separator character between items | | `ariaLabel` | `string` | `'Breadcrumb'` | Accessible label for the nav landmark | ### CoarBreadcrumbItem Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `active` | `boolean` | `false` | Mark as the current/active page (not a link) | ### CoarBreadcrumbItem Slots | Slot | Description | |------|-------------| | `default` | Item content -- typically an anchor tag for links, or plain text for the active item | --- --- url: /components/button.md --- # Button Buttons trigger actions and communicate what will happen when pressed. ```ts import { CoarButton } from '@cocoar/vue-ui'; ``` ## Variants Choose the appropriate variant based on the action's importance and context. **When to use each variant:** * **Primary** — Main call-to-action. Use sparingly, typically once per view. * **Secondary** — Alternative actions. Pairs well with primary buttons. * **Tertiary** — Low-emphasis actions with brand color hint. * **Danger** — Destructive actions like delete or remove. * **Ghost** — Minimal emphasis, often for cancel or dismiss. ## Sizes Four sizes to fit different contexts and layouts. ## Icons Add icons before or after the label to enhance meaning. ## Loading State Show a spinner while an async action is in progress. Click to test. ## Disabled State Disable buttons when actions are not available. ## Full Width Buttons can expand to fill their container. ## Accessibility ### Keyboard Navigation | Key | Action | |-----|--------| | `Tab` | Move focus to button | | `Shift + Tab` | Move focus backward | | `Enter` | Activate button | | `Space` | Activate button | ::: info Disabled and loading buttons cannot be activated via keyboard. ::: ### Screen Reader Support * Button text or `aria-label` announces on focus * Disabled state properly communicated * Loading state indicates button is busy * Icon-only buttons should include `aria-label` * `type` attribute ensures correct form behavior ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'danger' \| 'ghost'` | `'primary'` | Button style variant | | `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Button size | | `iconStart` | `string` | `undefined` | Icon name before label | | `iconEnd` | `string` | `undefined` | Icon name after label | | `loading` | `boolean` | `false` | Show loading spinner | | `disabled` | `boolean` | `false` | Disable the button | | `fullWidth` | `boolean` | `false` | Expand to fill container | | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | HTML button type | ### Events | Event | Payload | Description | |-------|---------|-------------| | `click` | `MouseEvent` | Emitted when clicked (not when disabled/loading) | ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.button.loading` | `'Loading'` | Screen reader announcement when `loading` is true | --- --- url: /components/card.md --- # Card Cards group related content into a visually distinct container, making it easy for users to scan and interact with discrete chunks of information. Use them for dashboards, content feeds, settings panels, or anywhere you need clear visual boundaries. ```ts import { CoarCard } from '@cocoar/vue-ui'; ``` ## Basic Usage A straightforward card with a title and body text. Cards provide structure without imposing rigid layout rules -- just slot in whatever content you need. ## Elevated vs Outlined Choose `elevated` for cards that need to stand out from the page (primary content), or `outlined` for a subtler border-based style that sits flatter in the layout. ## Color Variants Semantic color variants add a tinted background to convey meaning at a glance -- info for tips, success for confirmations, warning and error for alerts. ## Padding Sizes Adjust internal spacing to suit your content density. Use `s` for compact data cards, `m` for general use, and `l` when the card is the primary focus of the page. ## Rich Content Example Cards shine when combining multiple elements. Here a header, tags, body text, and action buttons work together inside a single card. ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `variant` | `'neutral' \| 'outlined' \| 'info' \| 'success' \| 'warning' \| 'error' \| 'accent'` | `'neutral'` | Card color/style variant | | `padding` | `'none' \| 's' \| 'm' \| 'l'` | `'m'` | Internal padding size | | `elevated` | `boolean` | `false` | Add box shadow for elevation | | `borderless` | `boolean` | `false` | Hide the border | ### Slots | Slot | Description | |------|-------------| | `default` | Card content | | `#header` | Fixed header area | | `#footer` | Fixed footer area | | `#inset` | Full-width inset area (negative margins) | --- --- url: /components/checkbox.md --- # Checkbox Checkboxes let users pick one or more options from a list, or flip a single boolean on or off. Reach for a checkbox when the choice does not take effect until the user explicitly submits -- for instant toggles, consider a [Switch](/components/switch) instead. ```ts import { CoarCheckbox } from '@cocoar/vue-ui'; ``` ## Basic Usage Bind a boolean with `v-model` and provide a `label`. That is all you need for a working checkbox. ## States Checkboxes support `required`, `disabled`, and `error` states, giving you full control over form validation flows. ## Indeterminate The indeterminate state shows a dash instead of a checkmark -- handy for "select all" controls where only some children are checked. ## Sizes Four sizes to match different information densities, from compact data tables to spacious settings pages. ## Hint Text Wrap in `CoarFormField` with a `hint` prop to give users extra context without cluttering the label itself. ## Without Label For table rows or tight custom layouts you can omit the visible label -- just make sure to pass an `aria-label` so the checkbox remains accessible. ## Accessibility ### Keyboard Navigation | Key | Action | |-----|--------| | `Tab` | Move focus to checkbox | | `Space` | Toggle checked state | ::: info The indeterminate state is visual only. Clicking an indeterminate checkbox toggles it to checked. Always provide `aria-label` when no visible label is used. ::: ### Screen Reader Support * Label text or `aria-label` announces on focus * Checked / unchecked state communicated * Required and error states announced * Hint text accessible via `aria-describedby` ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `v-model` | `boolean` | `false` | Checked state | | `label` | `string` | `''` | Label text | | `error` | `boolean` | `false` | Error state (auto-injected from `CoarFormField`) | | `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Checkbox size | | `indeterminate` | `boolean` | `false` | Show indeterminate (dash) state | | `disabled` | `boolean` | `false` | Disable the checkbox | | `required` | `boolean` | `false` | Mark as required | --- --- url: /components/code-block.md --- # Code Block Display source code with syntax highlighting, a one-click copy button, and optional collapsing. Use it in documentation, onboarding flows, or anywhere users need to read or copy code snippets. ```ts import { CoarCodeBlock } from '@cocoar/vue-ui'; ``` ## Language Support Built-in highlighting for TypeScript, HTML, CSS, Bash, JSON, and more. The language is detected from the `language` prop, so colors and tokens always match the syntax. ## Collapsible Behavior Keep long snippets from dominating the page. Start them collapsed so users can expand on demand, or disable collapsing when the code should always be visible. ## Variants The default `neutral` variant uses a neutral background. Other variants color the header area to match semantic context — `info`, `success`, `warning`, `error`, or `accent`. ## With Line Numbers Enable line numbers for larger code blocks where users need to reference specific lines. ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `code` | `string` | `''` | The source code to display | | `language` | `string` | `'html'` | Syntax highlighting language | | `variant` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'error' \| 'accent'` | `'neutral'` | Header color variant | | `title` | `string` | `''` | Optional title/filename label | | `collapsible` | `boolean` | `true` | Show collapse/expand toggle | | `collapsed` | `boolean` | `false` | Start in collapsed state | | `showLineNumbers` | `boolean` | `false` | Show line numbers | | `showCopy` | `boolean` | `true` | Show copy-to-clipboard button | | `maxHeight` | `number` | `0` | Maximum height in px before scrolling (0 = no limit) | | `borderless` | `boolean` | `false` | Hide border and border-radius | | `elevated` | `boolean` | `false` | Add box shadow | ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.codeBlock.copy` | `'Copy'` | Copy button text | | `coar.ui.codeBlock.copied` | `'Copied!'` | Copy button text (after success) | | `coar.ui.codeBlock.failed` | `'Failed'` | Copy button text (after error) | | `coar.ui.codeBlock.copyLabel` | `'Copy code'` | Copy button `aria-label` | | `coar.ui.codeBlock.toggleVisibility` | `'Toggle code visibility'` | Collapse/expand button `aria-label` | | `coar.ui.codeBlock.code` | `'Code'` | Code block `aria-label` | --- --- url: /foundations/colors.md --- # Colors Cocoar's color system is built on two layers: **primitives** (the raw palette) and **semantic tokens** (purpose-driven aliases). Semantic tokens adapt to light and dark mode automatically — always use them in your components instead of referencing primitives directly. ## Color Primitives Six scales, ten shades each. These are the building blocks that semantic tokens reference under the hood. ::: tip When to use primitives Almost never. Use semantic tokens in component code. Primitives are useful only when defining new semantic tokens or building one-off illustrations. ::: ## Semantic Colors Semantic tokens give colors *meaning* — background, text, border, or status — so your UI stays consistent and adapts to theme changes without touching component code. ## Usage Example A realistic card built entirely with semantic tokens. Toggle light/dark mode to see every color adapt. ## Token Naming Convention All tokens follow a predictable pattern: ``` --coar-{usage}-{category}-{variant} ``` | Segment | Values | Examples | |---------|--------|----------| | **Usage** | `background`, `text`, `border`, `icon` | What the color is applied to | | **Category** | `neutral`, `brand`, `accent`, `semantic-{status}` | The color family | | **Variant** | `primary`, `secondary`, `tertiary`, `bold`, `subtle`, `hover`, `active`, `disabled` | Emphasis level or state | ## Token Reference ### Background | Token | Usage | |-------|-------| | `--coar-background-neutral-primary` | Default page / card surface | | `--coar-background-neutral-secondary` | Slightly raised surface | | `--coar-background-neutral-tertiary` | Subtle fill for inputs, hover states | | `--coar-background-accent-primary` | Primary accent (buttons, active states) | | `--coar-background-accent-secondary` | Lighter accent fill | | `--coar-background-accent-tertiary` | Subtlest accent fill | | `--coar-background-accent-hover` | Accent hover state | | `--coar-background-accent-active` | Accent pressed state | | `--coar-background-brand-primary` | Brand-colored surface | | `--coar-background-brand-secondary` | Lighter brand surface | | `--coar-background-brand-tertiary` | Subtlest brand surface | ### Text | Token | Usage | |-------|-------| | `--coar-text-neutral-primary` | Primary body text | | `--coar-text-neutral-secondary` | Supporting / secondary text | | `--coar-text-neutral-tertiary` | Placeholder, hint text | | `--coar-text-neutral-disabled` | Disabled text | | `--coar-text-accent-primary` | Accent-colored text (links, highlights) | | `--coar-text-accent-secondary` | Lighter accent text | | `--coar-text-brand-primary` | Brand-colored text | | `--coar-text-on-bold` | White text on bold / colored surfaces | ### Border | Token | Usage | |-------|-------| | `--coar-border-neutral-primary` | Strong border (emphasis) | | `--coar-border-neutral-secondary` | Default visible border | | `--coar-border-neutral-tertiary` | Subtle divider | | `--coar-border-accent-primary` | Accent border (focus rings) | | `--coar-border-accent-secondary` | Lighter accent border | | `--coar-border-input` | Input field border | | `--coar-border-input-hover` | Input border on hover | ### Status | Token | Usage | |-------|-------| | `--coar-background-semantic-success-bold` | Success background (solid) | | `--coar-background-semantic-success-subtle` | Success background (light) | | `--coar-background-semantic-error-bold` | Error background (solid) | | `--coar-background-semantic-error-subtle` | Error background (light) | | `--coar-background-semantic-warning-bold` | Warning background (solid) | | `--coar-background-semantic-warning-subtle` | Warning background (light) | | `--coar-background-semantic-info-bold` | Info background (solid) | | `--coar-background-semantic-info-subtle` | Info background (light) | | `--coar-text-semantic-success-bold` | Success text (strong) | | `--coar-text-semantic-error-bold` | Error text (strong) | | `--coar-text-semantic-warning-bold` | Warning text (strong) | | `--coar-text-semantic-info-bold` | Info text (strong) | --- --- url: /components/data-grid.md --- # Data Grid A powerful data grid built on AG Grid with Cocoar theming. Configure columns, sorting, selection, and cell renderers through a fluent builder API — no raw AG Grid config needed. ::: info Separate Package The Data Grid depends on AG Grid. Install it separately: ```bash pnpm add @cocoar/vue-data-grid ag-grid-community ag-grid-vue3 ``` ::: ```ts import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid'; ``` ## Basic Usage Define columns with `.field()`, `.header()`, and `.flex()` / `.width()`. Pass row data with `.rowData()`. ## Column Types Built-in renderers for dates, numbers, tags, and icons — no custom cell components needed. | Method | Description | |--------|-------------| | `.field(name)` | Plain text column | | `.date(field, format?)` | Formatted date display | | `.number(field)` | Numeric formatting | | `.tag(field, config)` | Renders a `CoarTag` with variant mapping | | `.icon(field, config?)` | Renders a `CoarIcon` | ## Row Selection Toggle between single-click and multi-select with checkboxes. ## Reactive Data Bind a `ref` with `.rowDataRef()` and the grid updates automatically when your data changes. ## Sorting Make columns sortable and set a default sort order. ```ts const builder = CoarGridBuilder.create() .columns([ (col) => col.field('name').header('Name').flex(1).sortable(), (col) => col.number('salary').header('Salary').width(120).sortable(), ]) .rowData(data) .defaultSort('name', 'asc'); ``` ## API ### CoarDataGrid Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `builder` | `CoarGridBuilder` | — | Grid configuration builder (required) | | `theme` | `Theme` | `cocoarTheme` | AG Grid theme override | ### CoarGridBuilder Methods | Method | Parameters | Description | |--------|-----------|-------------| | `.columns(defs)` | `ColumnDefFn[]` | Define column configuration | | `.rowData(data)` | `T[]` | Set static row data | | `.rowDataRef(ref)` | `Ref` | Bind reactive row data | | `.rowSelection(mode, opts?)` | `'single' \| 'multiple'` | Enable row selection | | `.defaultSort(field, dir)` | `string, 'asc' \| 'desc'` | Set default sort column | | `.rowClassRules(rules)` | `RowClassRules` | Conditional row CSS classes | ### CoarGridColumnBuilder Methods | Method | Parameters | Description | |--------|-----------|-------------| | `.field(name)` | `keyof T` | Set column data field | | `.header(text)` | `string` | Set column header text | | `.flex(value)` | `number` | Flexible column width | | `.width(px)` | `number` | Fixed column width | | `.fixedWidth(px)` | `number` | Non-resizable fixed width | | `.sortable()` | — | Enable column sorting | | `.date(field, format?)` | `keyof T, string?` | Date cell renderer | | `.number(field)` | `keyof T` | Number cell renderer | | `.tag(field, config)` | `keyof T, TagConfig` | Tag cell renderer | | `.icon(field, config?)` | `keyof T, IconConfig?` | Icon cell renderer | --- --- url: /components/date-picker.md --- # Date Picker A calendar-backed date picker that returns a `Temporal.PlainDate` -- a date without time or timezone. Perfect for birthdays, deadlines, due dates, and any scenario where "which day" is all that matters. ```ts import { CoarPlainDatePicker } from '@cocoar/vue-ui'; ``` ## Basic Usage Click the input to open a calendar dropdown. The selected value is a proper `Temporal.PlainDate`, so date math and formatting are straightforward. ## Required & Error States Combine `required` and `error` props for form validation. The required asterisk and error message integrate with the same patterns as every other Cocoar input. ## Disabled & Readonly `disabled` greys out the entire picker; `readonly` lets users see the selected date but prevents changes. ## Date Range (Manual) For start/end date pairs, use two pickers and pass the start date as `:min` on the end picker. This prevents users from selecting an end date before the start. ## Sizes Four sizes to stay consistent with other form controls across your layout. ::: info **Temporal.PlainDate:** This component uses the TC39 Temporal API (`@js-temporal/polyfill`). PlainDate represents a calendar date without time or timezone -- no more wrestling with midnight UTC offsets. ::: ## Accessibility ### Keyboard Navigation | Key | Action | |-----|--------| | `Tab` | Move focus to input / calendar | | `Enter` | Open calendar / select date | | `Escape` | Close calendar dropdown | | `Arrow Keys` | Navigate within the calendar | ### Screen Reader Support * Label text announces on focus * Selected date is read aloud * Calendar navigation is keyboard accessible * Required and error states announced ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `v-model` | `Temporal.PlainDate \| null` | `null` | Selected date | | `label` | `string` | `''` | Label text | | `placeholder` | `string` | `''` | Placeholder text | | `min` | `Temporal.PlainDate` | `undefined` | Minimum selectable date | | `max` | `Temporal.PlainDate` | `undefined` | Maximum selectable date | | `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Input size | | `disabled` | `boolean` | `false` | Disable the picker | | `readonly` | `boolean` | `false` | Make read-only | | `required` | `boolean` | `false` | Mark as required | | `error` | `string` | `''` | Error message | ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.datePicker.previousYear` | `'Previous year'` | Previous year button `aria-label` | | `coar.ui.datePicker.nextYear` | `'Next year'` | Next year button `aria-label` | | `coar.ui.datePicker.jumpToToday` | `'Jump to today\'s month'` | Scroll-to-today button `aria-label` | | `coar.ui.datePicker.months` | `'Months'` | Month grid `aria-label` | | `coar.ui.datePicker.dialog` | `'Date picker'` | Overlay dialog `aria-label` | | `coar.ui.datePicker.clearDate` | `'Clear date'` | Clear button `aria-label` | | `coar.ui.datePicker.openPicker` | `'Open picker'` | Calendar button `aria-label` | --- --- url: /components/date-time-picker.md --- # DateTime Picker Combines a calendar date picker with a time input and returns a `Temporal.PlainDateTime` -- a date and time without any timezone attached. Use this when the timezone is implicit (the user's local time) or irrelevant (an alarm, a reminder). If you need timezone awareness, reach for the [Zoned DateTime Picker](/components/zoned-date-time-picker) instead. ```ts import { CoarPlainDateTimePicker } from '@cocoar/vue-ui'; ``` ## Basic Usage Select a date from the calendar, then adjust the time. The bound value is a `Temporal.PlainDateTime` you can format, compare, or serialize as needed. ## States Supports `required`, `error`, `disabled`, and `readonly` -- the same set of states you will find on every Cocoar form control. ## Sizes Four sizes to match surrounding inputs and keep your forms visually balanced. ::: info **PlainDateTime vs ZonedDateTime:** Choose `PlainDateTime` when the timezone is always the user's local time or when it simply does not matter (alarm clocks, recurring events). Choose `ZonedDateTime` when you need to pin a specific instant in time and derive UTC for storage or sharing across timezones. ::: ## Accessibility ### Keyboard Navigation | Key | Action | |-----|--------| | `Tab` | Move focus between date and time inputs | | `Enter` | Open calendar / confirm selection | | `Escape` | Close calendar dropdown | | `Arrow Keys` | Navigate within the calendar | ### Screen Reader Support * Label text announces on focus * Date and time portions are independently accessible * Required and error states announced * Calendar navigation is keyboard accessible ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.dateTimePicker.dialog` | `'Date time picker'` | Overlay dialog `aria-label` | | `coar.ui.dateTimePicker.clearDate` | `'Clear date'` | Clear button `aria-label` | | `coar.ui.dateTimePicker.openPicker` | `'Open picker'` | Calendar button `aria-label` | | `coar.ui.datePicker.jumpToToday` | `'Jump to today\'s month'` | Scroll-to-today button `aria-label` | | `coar.ui.datePicker.previousYear` | `'Previous year'` | Previous year button `aria-label` | | `coar.ui.datePicker.nextYear` | `'Next year'` | Next year button `aria-label` | | `coar.ui.datePicker.months` | `'Months'` | Month grid `aria-label` | | `coar.ui.timePicker.increaseHours` | `'Increase hours'` | Hours increment button `aria-label` | | `coar.ui.timePicker.decreaseHours` | `'Decrease hours'` | Hours decrement button `aria-label` | | `coar.ui.timePicker.hours` | `'Hours'` | Hours spinbutton `aria-label` | | `coar.ui.timePicker.increaseMinutes` | `'Increase minutes'` | Minutes increment button `aria-label` | | `coar.ui.timePicker.decreaseMinutes` | `'Decrease minutes'` | Minutes decrement button `aria-label` | | `coar.ui.timePicker.minutes` | `'Minutes'` | Minutes spinbutton `aria-label` | ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `v-model` | `Temporal.PlainDateTime \| null` | `null` | Selected date+time | | `label` | `string` | `''` | Label text | | `placeholder` | `string` | `''` | Placeholder text | | `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Input size | | `disabled` | `boolean` | `false` | Disable the picker | | `readonly` | `boolean` | `false` | Make read-only | | `required` | `boolean` | `false` | Mark as required | | `error` | `string` | `''` | Error message | --- --- url: /foundations/design-principles.md --- # Design Principles The foundation of the Cocoar Design System — six principles that guide every design decision across our Vue 3 component library. *** ### Clarity Every element has a clear purpose. Reduce visual noise and make the important thing obvious. * Consistent spacing creates visual rhythm that guides scanning * Typography hierarchy directs attention to what matters most * Limit each view to one primary action to reduce decision fatigue * Use whitespace generously — empty space is not wasted space *** ### Consistency Use the same patterns, tokens, and components everywhere. Predictability reduces cognitive load and builds trust. * Shared token vocabulary across colors, spacing, radius, and motion * Uniform component API patterns — props, events, and slots follow conventions * Consistent interaction models — similar controls behave identically * One way to do things, not many — fewer choices lead to better outcomes *** ### Accessibility Design for everyone. Meet WCAG AA standards at minimum. Keyboard navigation is not optional — it is a core feature. * **4.5 : 1** minimum contrast ratio for all text content * Full keyboard navigation built into every interactive component * Screen reader support with proper ARIA attributes * Focus indicators that are visible and consistent * Respect `prefers-reduced-motion` for users who need it *** ### Touch-First All components work with **touch and focus** — hover is an enhancement, not a requirement. This is **tablet-first** design: touch interaction with desktop-appropriate information density. Not mobile-first — mobile phones have different constraints (small screens, portrait orientation, one-handed use). Tablets have similar screen real estate to laptops but use touch instead of mouse. * Minimum **44 x 44 px** touch targets on all interactive elements * Appropriate tap spacing to prevent accidental activation * No hover-only interactions — every feature is reachable via tap or keyboard * Use dimmed states instead of hiding; on focus/hover elements become prominent * Desktop gets additional polish (hover states) as progressive enhancement *** ### Performance Ship less, load faster. Icons are inlined SVGs. Components are tree-shakeable. CSS theming uses custom properties for zero runtime cost. * Inline SVG icons eliminate icon font overhead * Individual component imports enable dead-code elimination * CSS custom property theming — no JavaScript at render time * Lightweight component architecture with minimal dependencies *** ### Developer Experience Strong TypeScript types. Composable APIs. Predictable naming. The system should be a joy to use, not a chore to learn. * Full TypeScript support with exported types for every component * Consistent `v-model` patterns across all form controls * Self-documenting prop names — no guessing what `mode="3"` means * Composable utilities (`useDialog`, `useToast`) for programmatic control *** ## Design Token Architecture Cocoar uses a **two-layer token system**: raw primitives are referenced by semantic tokens. Always use semantic tokens in your components — they adapt automatically to light and dark mode. | Category | Token Prefix | Description | |---|---|---| | **Color** | `--coar-color-*` | Raw color primitives (gray, slate, accent, green, red, amber) | | **Background** | `--coar-background-*` | Semantic surface tokens for accent, brand, neutral, and status | | **Text** | `--coar-text-*` | Text color tokens for all states and emphasis levels | | **Border** | `--coar-border-*` | Border color tokens for interactive and structural elements | | **Spacing** | `--coar-spacing-*` | Space scale from `xxs` (2 px) to `xxxl` (64 px) on a 4 px grid | | **Radius** | `--coar-radius-*` | Border radius from `xxs` (1 px) to `full` (999 px) | | **Shadow** | `--coar-shadow-*` | Elevation shadows `xs`–`xl` plus a focus ring | | **Typography** | `--coar-titles-*` / `--coar-headings-*` / `--coar-body-*` | Font family, size, and weight tokens for each text role | | **Motion** | `--coar-duration-*` / `--coar-ease-*` / `--coar-transition-*` | Duration, easing, and pre-composed transition tokens | ## Do's and Don'ts ::: tip Do * Use semantic tokens — `--coar-text-neutral-primary`, not a raw hex value * Follow the **4 px spacing grid** for all layout dimensions * Use `v-model` for two-way binding on form controls * Import components individually for tree-shaking: `import { CoarButton } from '@cocoar/vue-ui'` * Test keyboard navigation for every interactive flow * Provide `aria-label` for icon-only buttons ::: ::: danger Don't * Hardcode colors or spacing values in component styles * Use primitive tokens directly in components (`--coar-color-gray-500`) * Override component internals with `:deep()` selectors * Create hover-only interactions that exclude touch and keyboard users * Mix spacing values that are not on the 4 px grid * Ignore `prefers-reduced-motion` in custom animations ::: ::: info Dark Mode Toggle dark mode by adding the `.dark-mode` class to `document.documentElement`. All tokens and components update automatically — no JavaScript required at render time. ::: --- --- url: /components/dialog.md --- # Dialog Modal dialogs demand attention. They block interaction with the rest of the page until the user makes a decision, making them the right choice for destructive actions, important confirmations, and messages that must be acknowledged before proceeding. Use them sparingly -- when the stakes are high enough to justify interrupting the user's flow. ```ts import { useDialog } from '@cocoar/vue-ui'; ``` ## Confirm Dialog Use `dialog.confirm()` when you need an explicit yes-or-no decision before proceeding. The returned promise resolves with `true` (confirmed) or `false` / `undefined` (cancelled / dismissed). ## Alert Dialog Use `dialog.alert()` for one-way messages that require acknowledgement -- session expirations, permission errors, or completion notices. The user can only dismiss it; there is no secondary action. ## Setup Register the overlay plugin once in your app entry point: ```ts // main.ts import { CoarOverlayPlugin } from '@cocoar/vue-ui'; createApp(App) .use(CoarOverlayPlugin) .mount('#app'); ``` ::: warning Dialog vs Popconfirm Use **Dialog** for modal confirmations that block the entire UI. Use **Popconfirm** for lightweight inline confirmations anchored near the trigger element. Dialogs are appropriate for higher-stakes, less frequent actions. ::: ## API ### `useDialog()` Methods | Method | Parameters | Returns | Description | |--------|-----------|---------|-------------| | `dialog.confirm(options)` | `ConfirmOptions` | `DialogRef` | Show a confirm/cancel dialog | | `dialog.alert(title, message)` | `string, string` | `DialogRef` | Show an acknowledgement dialog | | `dialog.open(component, config?, props?)` | `Component, DialogConfig?, Record?` | `DialogRef` | Open a custom component inside the dialog | ### `ConfirmOptions` | Option | Type | Default | Description | |--------|------|---------|-------------| | `title` | `string` | — | Dialog title | | `message` | `string` | — | Confirmation message body | | `confirmText` | `string` | `'Confirm'` | Confirm button label | | `cancelText` | `string` | `'Cancel'` | Cancel button label | | `confirmVariant` | `'primary' \| 'danger'` | `'primary'` | Confirm button color variant | | `size` | `'s' \| 'm' \| 'l'` | `'s'` | Dialog width | ### `DialogRef` | Property | Type | Description | |----------|------|-------------| | `result` | `Promise` | Resolves when the dialog closes | | `close(result?)` | `(val?: T) => void` | Programmatically close the dialog | ## i18n Keys These keys can be translated via [`@cocoar/vue-localization`](/guide/i18n). | Key | Default (English) | Used as | |-----|-------------------|---------| | `coar.ui.dialog.close` | `'Close dialog'` | Close button `aria-label` | | `coar.ui.dialog.dialog` | `'Dialog'` | Fallback dialog `aria-label` (when no title) | --- --- url: /components/divider.md --- # Divider Dividers create clear visual breaks between sections of content. They're especially useful in forms, settings panels, and feeds where distinct groups of information sit close together. Add an optional text label to give the break semantic meaning. ```ts import { CoarDivider } from '@cocoar/vue-ui'; ``` ## Basic Divider A clean horizontal line that separates content blocks. Drop it between any two sections to improve scannability. ## With Content Embed text directly in the divider line via the default slot -- common in forms ("or continue with") and settings pages. ## Alignment Position the content to the `left`, `center`, or `right` of the line to match your layout's reading flow. ## Variants Two visual weights: `subtle` (the default) for light separation within a card, and `strong` for more prominent visual breaks. ## Real-world Usage A classic login form pattern where a labeled divider separates OAuth sign-in buttons from the traditional email/password fields. ## API ### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `align` | `'left' \| 'center' \| 'right'` | `'center'` | Content alignment | | `variant` | `'subtle' \| 'strong'` | `'subtle'` | Line visual weight | | `width` | `number` | `90` | Divider width as a percentage (0–100) | | `spacingTop` | `number` | `0` | Top spacing in pixels | | `spacingBottom` | `number` | `0` | Bottom spacing in pixels | ### Slots | Slot | Description | |------|-------------| | `default` | Optional content displayed centered on the line | --- --- url: /guide/error-handling.md --- # Error Handling Cocoar UI components are designed to fail gracefully. Internal errors are either caught and recovered silently, or surfaced to the user through controlled feedback mechanisms. This guide explains the patterns used throughout the library and how to handle errors in your own application code. ## Library Philosophy: Fail Gracefully Components never throw unhandled exceptions into your application. Instead they follow one of two patterns: * **Silent fallback** — return a safe default (`null`, `'UTC'`, `false`) and continue * **User feedback** — surface the error visibly via a Toast or state change ## Overlay Promises `CoarDialog` and `CoarPopconfirm` return Promises. Always handle the rejection case: ```ts import { useDialog } from '@cocoar/vue-ui'; const dialog = useDialog(); // ✅ Always add .catch() dialog.confirm({ title: 'Delete item', message: 'This cannot be undone.', }) .then((confirmed) => { if (confirmed) deleteItem(); }) .catch(() => { // Dialog was closed unexpectedly (e.g. overlay destroyed before user responded) }); ``` With async/await: ```ts try { const confirmed = await dialog.confirm({ title: 'Delete item', message: '...' }); if (confirmed) await deleteItem(); } catch { // Handle unexpected close } ``` ::: tip Popconfirm `CoarPopconfirm` emits `@confirmed` and `@cancelled` events — no Promise handling needed there. Use it for simple inline confirmations, and reserve `useDialog()` for programmatic flows where error handling is more important. ::: ## Toast for Error Feedback Use `useToast().error()` to surface errors to the user. Error toasts are persistent by default (duration `0`) — they stay until the user dismisses them, which is appropriate for errors that require attention. ```ts import { useToast } from '@cocoar/vue-ui'; const toast = useToast(); async function saveData() { try { await api.save(payload); toast.success('Saved successfully'); } catch (err) { toast.error('Save failed', { message: err instanceof Error ? err.message : 'Please try again.', }); } } ``` ```ts // With a retry action toast.error('Connection lost', { message: 'Could not reach the server.', action: { label: 'Retry', callback: () => saveData(), }, }); ``` ## Date and Time Parsing Date parsing functions return `null` on failure instead of throwing. Always null-check the result before using it: ```ts import { coarParsePlainDate } from '@cocoar/vue-ui'; const date = coarParsePlainDate(userInput); if (date === null) { // Input was invalid — show validation error toast.error('Invalid date format'); return; } // date is a Temporal.PlainDate — safe to use processDate(date); ``` The date picker components handle this internally — invalid input simply doesn't update the model value. Your `v-model` will remain `null` until the user enters a valid date. ## Timezone Fallbacks Timezone utilities default to `'UTC'` when the browser API fails or the timezone identifier is unrecognised. This keeps date/time components functional even in restricted environments: ```ts import { useTimezone } from '@cocoar/vue-localization'; const { timezone } = useTimezone(); // Always a valid IANA identifier — 'UTC' as last resort ``` ## Async Operations in Overlays When loading data inside a Dialog or Popover, manage loading and error states yourself: ```vue ``` ## Pattern Summary | Situation | Recommended pattern | |-----------|---------------------| | Dialog/Popconfirm result | `.then().catch()` or `try/await/catch` | | API call in component | `try/catch` + `toast.error()` | | Date input validation | Null-check return value of parse functions | | Non-recoverable error | `toast.error()` with persistent duration (default) | | Recoverable error | `toast.error()` with `action: { label: 'Retry', callback }` | | Silent failures OK | Rely on library defaults (`null`, `'UTC'`, `false`) | --- --- url: /components/form-field.md --- # Form Field A wrapper component that provides a label, hint text, and error message around any form control. Instead of each input managing its own label and validation display, `CoarFormField` handles these concerns in one place. ```ts import { CoarFormField } from '@cocoar/vue-ui'; ``` ## Basic Usage Wrap any form control in `CoarFormField` and pass `label`, `hint`, or `error` props. The label is automatically associated with the input inside via generated IDs. ## Grouping Controls Use `CoarFormField` to add a group label and shared error to a set of checkboxes or radio buttons. Each checkbox keeps its own inline `label` prop for the option text. ## Registration Form A complete registration form with submit-on-click validation. Errors only appear after the user attempts to submit. ## Settings Panel A settings page using every form control type — text inputs, textareas, selects, checkboxes, radio groups, and switches — all wrapped in `CoarFormField` for consistent layout. ## Validation with vee-validate `CoarFormField` integrates seamlessly with [vee-validate](https://vee-validate.logaretm.com/) and [Zod](https://zod.dev/) schemas. Use `useField()` to get reactive `value` and `errorMessage` refs, then bind them to the input and `CoarFormField` respectively. ::: tip Other validation libraries `CoarFormField` is library-agnostic — it just takes an `error` string. Any validation approach works: vee-validate, vuelidate, or plain computed properties. ::: ## Standalone Form Controls Form controls work without `CoarFormField` when no label or validation is needed — inline search inputs, table checkboxes, toolbar buttons. ```vue ``` ## Accessibility `CoarFormField` generates unique IDs automatically: * **Label**: `