Skip to content
Feedback

Feedback

Every component, with its variants, sizes and states. Change the appearance here and every sample follows.

Alert

A message that belongs to the screen and stays until the situation changes.

Tones

Prices include VAT for customers in the EU.
Information
Your payout of €2,480.00 is on its way.
Success
Three products are out of stock.
Warning
Danger
<div class="or-alert or-alert--warning" role="status">
  <svg class="or-i or-i-18" aria-hidden="true"><use href="#or-i-triangle-alert"></use></svg>
  <div>Three products are out of stock.</div>
</div>
<div className="or-alert or-alert--warning" role="status">
  <Icon name="triangle-alert" size={18} />
  <div>Three products are out of stock.</div>
</div>
<div class="or-alert or-alert--warning" role="status">
  <Icon name="triangle-alert" :size="18" />
  <div>Three products are out of stock.</div>
</div>
<div className="or-alert or-alert--warning" role="status">
  <Icon name="triangle-alert" size={18} />
  <div>Three products are out of stock.</div>
</div>
<div class="or-alert or-alert--warning" role="status">
  <Icon name="triangle-alert" :size="18" />
  <div>Three products are out of stock.</div>
</div>

Toast

The result of something the reader just did. It leaves on its own.

Tones

Export started. It will be ready in a minute.
Information
Saved
Success
Nothing was saved.
Danger
<script>
  window.Orion.toast('Saved', 'success')
</script>
const push = useToasts((state) => state.push)
push(t('form.saved'), 'success')
const toasts = useToasts()
toasts.push(t('form.saved'), 'success')
// Server actions answer in place: the island shows the result inline
// rather than in a toast, so it is still there after a redirect.
<p className="or-alert or-alert--success" role="status">{t('form.saved')}</p>
const toasts = useToasts()
toasts.push(t('form.saved'), 'success')

Skeleton

The shape of what is loading, so the page can be read before the numbers land.

Variants

Text
Value
Block
<span class="or-skel or-skel--value"></span>
<span class="or-skel or-skel--text" style="inline-size: 40%"></span>
<Skeleton variant="value" />
<Skeleton width="40%" />
<Skeleton variant="value" />
<Skeleton width="40%" />
<Skeleton variant="value" />
<Skeleton width="40%" />
<Skeleton variant="value" />
<Skeleton width="40%" />

Empty state

Says why there is nothing here and offers the way out.

Used in the demo at /orders

Variants

Nothing matches those filters

Try a different search, or clear the filters to see everything again.

With an action
<div class="or-empty">
  <span class="or-empty__mark">
    <svg class="or-i or-i-24" aria-hidden="true"><use href="#or-i-search"></use></svg>
  </span>
  <h3>Nothing matches those filters</h3>
  <p class="or-muted">Try a different search.</p>
</div>
<EmptyState icon="search" title={t('table.noResults')} body={t('table.noResultsBody')}>
  <button type="button" className="or-btn" onClick={table.clearFilters}>{t('table.clearFilters')}</button>
</EmptyState>
<EmptyState icon="search" :title="t('table.noResults')" :body="t('table.noResultsBody')">
  <button type="button" class="or-btn" @click="table.clearFilters">{{ t('table.clearFilters') }}</button>
</EmptyState>
<EmptyState icon="search" title={t('table.noResults')} body={t('table.noResultsBody')}>
  <button type="button" className="or-btn" onClick={table.clearFilters}>{t('table.clearFilters')}</button>
</EmptyState>
<EmptyState icon="search" :title="t('table.noResults')" :body="t('table.noResultsBody')">
  <button type="button" class="or-btn" @click="table.clearFilters">{{ t('table.clearFilters') }}</button>
</EmptyState>

Form bar

What is unsaved and the two things to do about it, stuck to the bottom of the form.

Used in the demo at /settings

States

Saved

Saved

Unsaved changes

Unsaved

2 fields need attention

Error

Unsaved changes

Loading
<div class="or-formbar">
  <p class="or-formbar__state" role="status" data-or-formstate></p>
  <span class="or-push"></span>
  <button type="button" class="or-btn or-btn--ghost" data-or-discard disabled>Discard changes</button>
  <button type="submit" class="or-btn or-btn--primary" data-or-save disabled>Save changes</button>
</div>
<FormBar
  dirty={form.dirty}
  saving={save.isPending}
  errors={form.errorCount}
  onSave={() => form.submit(() => save.mutate())}
  onDiscard={form.discard}
/>
<FormBar
  :dirty="form.dirty.value"
  :saving="save.isPending.value"
  :errors="form.errorCount.value"
  @save="form.submit(() => save.mutate())"
  @discard="form.discard()"
/>
<FormBar
  dirty={form.dirty}
  saving={save.isPending}
  errors={form.errorCount}
  onSave={() => form.submit(() => save.mutate())}
  onDiscard={form.discard}
/>
<FormBar
  :dirty="form.dirty.value"
  :saving="save.isPending.value"
  :errors="form.errorCount.value"
  @save="form.submit(() => save.mutate())"
  @discard="form.discard()"
/>

Confirm dialog

Stands between the reader and losing their work. Escape is the safe answer.

Variants

Unsaved changes

Leaving this screen now loses them.

Confirmation
<div class="or-modal">
  <div class="or-dialog" role="alertdialog" aria-modal="true" aria-labelledby="leave-title">
    <h3 id="leave-title">Unsaved changes</h3>
    <p>Leaving this screen now loses them.</p>
    <div class="or-dialog__actions">
      <button type="button" class="or-btn">Stay here</button>
      <button type="button" class="or-btn or-btn--danger">Leave anyway</button>
    </div>
  </div>
</div>
<ConfirmDialog
  open={guard.pending !== null}
  title={t('form.unsaved')}
  body={t('form.unsavedBody')}
  confirmLabel={t('form.leave')}
  onConfirm={guard.leave}
  onCancel={guard.stay}
/>
<ConfirmDialog
  :open="guard.pending.value !== null"
  :title="t('form.unsaved')"
  :body="t('form.unsavedBody')"
  :confirm-label="t('form.leave')"
  @confirm="guard.leave"
  @cancel="guard.stay"
/>
<ConfirmDialog
  open={guard.pending !== null}
  title={t('form.unsaved')}
  body={t('form.unsavedBody')}
  confirmLabel={t('form.leave')}
  onConfirm={guard.leave}
  onCancel={guard.stay}
/>
<FormConfirmDialog
  :open="guard.pending.value !== null"
  :title="t('form.unsaved')"
  :body="t('form.unsavedBody')"
  :confirm-label="t('form.leave')"
  @confirm="guard.leave"
  @cancel="guard.stay"
/>