Components

The @codecora/ui primitives on bits-ui. Every control works with the keyboard alone; switch theme, accent and density to check them.

Jump to a section

State matrix

Every state a control can be in, in the theme and density chosen above. Hover and focus need your pointer and keyboard: hover a control, or press Tab to see the focus ring each theme draws.

ControlDefaultDisabledLoadingInvalid
Button–
Danger button–
Icon button––
Input–

Error: Enter name@example.com.

Select
–

Error: Choose a region.

Textarea–

Error: Keep notes under 200 characters.

Checkbox
–
Switch
––
Combobox
–

Error: Choose a region.

Slider
Retention
Retention (locked)
––
BadgeNeutral Accent Success Warning Danger
Props
<Button variant="primary|secondary|ghost|danger" icon={Icon} loading loadingLabel="Saving" href disabled />
<IconButton icon={Icon} label="Required, names the action" variant disabled />
<Field label description error required>
  {#snippet children(control)}<Input {...control} bind:value />{/snippet}
</Field>
<Select items={[{ value, label, disabled? }]} bind:value />
<Badge tone="neutral|accent|success|warning|danger" />
<Checkbox label checked indeterminate invalid disabled onchange />
<Switch label checked disabled />
<RadioGroup label items={[{ value, label, description?, disabled? }]} bind:value />
<Combobox items bind:value label emptyText />   <!-- needs a label or a Field -->
<Slider label bind:value min max step format showValue />
<Table label="Required, names the table" />   <!-- tr[data-selected="true"] marks a row -->

Buttons

As a link
Loading keys
Show the code
svelte
<script>
  import { Button, IconButton, Tooltip } from '@codecora/ui';
  import { Copy, Plus } from '@codecora/icons/lucide';
</script>

<Button variant="primary" icon={Plus}>Create key</Button>
<Button variant="danger" loading={saving} loadingLabel="Revoking">Revoke</Button>
<Tooltip content="Copy key">
  {#snippet trigger({ props })}
    <IconButton {...props} icon={Copy} label="Copy key" />
  {/snippet}
</Tooltip>

Form fields

Shown in the audit log.

Where the data lives.

Read only while the plan is paused.

Invalid state

An icon and a screen-reader "Error:" prefix back the red text, and the control gets a stronger border, so the state never depends on colour alone.

Error: Enter an address like name@example.com.

Error: Choose a region to continue.

Error: Notes are limited to 200 characters.

Show the code
svelte
<script>
  import { Field, Input, Select } from '@codecora/ui';
  let name = $state('');
</script>

<Field label="Key name" description="Shown in the audit log." error={error} required>
  {#snippet children(control)}
    <Input {...control} bind:value={name} />
  {/snippet}
</Field>
<Field label="Region">
  {#snippet children(control)}
    <Select {...control} items={regions} bind:value={region} />
  {/snippet}
</Field>

Checkbox, Switch, RadioGroup

Checkbox

Emailed after each payment.

Accept the terms to continue.

Switch

At most one a day.

RadioGroup

A summary every morning.

Mondays, 09:00.

Show the code
svelte
<script>
  import { Checkbox, RadioGroup, Switch } from '@codecora/ui';
</script>

<Checkbox label="All keys" bind:checked={all} bind:indeterminate={mixed} />
<Switch label="Email alerts" description="At most one a day." bind:checked={alerts} />
<RadioGroup label="Digest" items={digests} bind:value={digest} />

Combobox, Slider, FieldGroup

Type to filter.

Error: Choose a region to continue.

Retention 30 days
Digest

How often we email you.

Show the code
svelte
<script>
  import { Combobox, Field, Slider } from '@codecora/ui';
</script>

<Field label="Region">
  {#snippet children(control)}
    <Combobox {...control} items={regions} bind:value={region} />
  {/snippet}
</Field>
<Slider label="Retention" bind:value={days} min={7} max={90} showValue
  format={(v) => `${v} days`} />

Dialog, ConfirmDialog, Sheet, Toast

Show the code
svelte
<script>
  import { ConfirmDialog, Toaster, toast } from '@codecora/ui';
  let open = $state(false);
</script>

<ConfirmDialog
  bind:open
  title="Revoke ci-deploy?"
  description="Anything using this key stops working immediately."
  confirmLabel="Revoke key"
  confirmText="ci-deploy"
  tone="danger"
  onconfirm={() => toast.success('Key revoked')}
/>
<Toaster />

Breadcrumb, Accordion, ToggleGroup, Pagination, Popover, Menu

Invoices are emailed on the first of the month.
or press Ctrl K

Page 3 of 24

Show the code
svelte
<script>
  import { Breadcrumb, Pagination, ToggleGroup } from '@codecora/ui';
</script>

<Breadcrumb items={[{ label: 'Home', href: '/' }, { label: 'ci-deploy' }]} />
<ToggleGroup label="View" bind:value={view}
  items={[{ value: 'list', label: 'List' }, { value: 'grid', label: 'Grid' }]} />
<Pagination count={240} perPage={10} bind:page />

Tabs and Table

Show the code
svelte
<script>
  import { Tabs } from '@codecora/ui';
</script>

<Tabs label="Key views" items={[{ value: 'keys', label: 'Keys' }, { value: 'usage', label: 'Usage' }]}>
  {#snippet panel(value)}
    {value === 'keys' ? 'Keys table' : 'Usage chart'}
  {/snippet}
</Tabs>

DataTable

API keys
Scope
ci-deployread, writeActive12,840
dashboardreadActive3,112
old-importerread, writeRevoked0
staging-botreadExpiring411
billing-syncreadActive930
Show the code
svelte
<script>
  import { DataTable } from '@codecora/ui';
  const columns = [
    { key: 'name', label: 'Name', sortable: true },
    { key: 'calls', label: 'Calls (30 d)', sortable: true, numeric: true },
  ];
</script>

<DataTable label="API keys" {columns} {rows} rowKey={(row) => row.id}
  selectable bind:selected bind:page pageSize={5} />

Card, Alert, Avatar, Progress and friends

Memory plan

12,480 of 50,000 memories stored. Resets on the 1st.

Memories 25%

New

Search now matches tags.
Key saved.

Quota

80% of the monthly limit is used.
A neutral note without a title.
Press Ctrl K to search, Esc to close.
bash
bun add https://github.com/codecoradev/codecora-ui/releases/download/v0.7.0/codecora-ui-0.6.0.tgz
Show the code
svelte
<script>
  import { Alert, Avatar, Progress } from '@codecora/ui';
</script>

<Alert tone="warning" title="Quota">80% of the monthly limit is used.</Alert>
<Progress label="Memories" value={12480} max={50000} showValue />
<Avatar name="Ada Lovelace" />

Badge, Skeleton, EmptyState

Neutral Accent Success Warning Danger

No keys yet

Create an API key to connect a tool to your memory.

Show the code
svelte
<script>
  import { Badge, Button, EmptyState } from '@codecora/ui';
  import { Inbox } from '@codecora/icons/lucide';
</script>

<Badge tone="success">Active</Badge>
<EmptyState icon={Inbox} title="No keys yet" description="Create an API key to connect a tool.">
  {#snippet action()}<Button variant="primary">Create key</Button>{/snippet}
</EmptyState>