Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Huskarl AI colleagues on your own Mac Starf An activity monitor for Apple silicon that never invents a number etrans An SSH and SFTP client for macOS Elyra VM Virtual machines for macOS, Linux and Windows on your Mac Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra Workspace A desktop workspace for coding agents Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra

Button

A button, or a link that looks like one. It knows the user's abilities, can ask before it acts, and shows when the form it submits is saving.

Examples
<script>
  import { Button } from "@elyra/ui";
</script>

<Button variant="primary">New customer</Button>
<Button>Export</Button>
<Button variant="ghost">Cancel</Button>
<Button variant="danger">Delete</Button>

Use one primary button for a screen's main action. danger is for what destroys, and ghost is for what's quiet: a cancel, a toolbar's tools.

Sizes

sm is for toolbars, table rows and anywhere dense.

<script>
  import { Button } from "@elyra/ui";
</script>

<Button variant="primary">Medium</Button>
<Button variant="primary" size="sm">Small</Button>
<Button size="sm">Small</Button>

Busy and disabled

loading shows a spinner and sets aria-busy. The button can't be pressed while it's busy. Inside a Form, a type="submit" button is busy on its own while the form saves.

<script>
  import { Button } from "@elyra/ui";

  let syncing = $state(false);

  async function sync() {
    syncing = true;
    await new Promise((resolve) => setTimeout(resolve, 1500));
    syncing = false;
  }
</script>

<Button variant="primary" loading={syncing} onclick={sync}>Sync now</Button>
<Button disabled>Archived</Button>

Links

With href it's a link. An app path (/customers/7) goes through the app's router. Any other URL is used as it is, and other attributes, like target, go to the <a>. A disabled or busy link is drawn as a disabled button.

<script>
  import { Button } from "@elyra/ui";
  import { route } from "@elyra/runtime";
</script>

<Button href="/customers/7">Open Ada Lovelace</Button>
<Button variant="ghost" href="https://elyracode.com/framework" target="_blank">The website</Button>
<span>The app is at <code>{$route.path}</code></span>

What the user may do

can names an ability. A user without it doesn't see the button, or, with canMode="disable", sees it disabled. The abilities come from Laravel (RFC 0010), or from the app's own grants when it has no backend. Hiding a button doesn't protect anything: the command, and Laravel, still refuse.

<script>
  import { Button } from "@elyra/ui";
</script>

<!-- The user may export customers, but not delete them. -->
<Button can="customers.export">Export</Button>
<Button variant="danger" can="customers.delete">Delete (hidden)</Button>
<Button variant="danger" can="customers.delete" canMode="disable">Delete</Button>

In these docs the user may do everything but customers.delete.

Asking first

confirm asks in the runtime's dialog, the one confirm() from @elyra/runtime opens, before onclick runs. confirmLabel names the dialog's button. A danger button's dialog is a danger one. On a link or a submit button, the yes follows the link or submits the form.

<script>
  import { Button } from "@elyra/ui";

  let deleted = $state(false);
</script>

<Button
  variant="danger"
  confirm="Delete Ada Lovelace? Her 12 invoices stay in the accounts."
  confirmLabel="Delete customer"
  onclick={() => (deleted = true)}
>
  Delete customer
</Button>
{#if deleted}<span>Deleted.</span>{/if}

ButtonGroup

Buttons that belong together, joined. label names the group for a screen reader.

<script>
  import { Button, ButtonGroup } from "@elyra/ui";

  let view = $state("list");
</script>

<ButtonGroup label="View">
  {#each ["list", "board", "calendar"] as option (option)}
    <Button size="sm" variant={view === option ? "primary" : "default"} aria-pressed={view === option} onclick={() => (view = option)}>
      {option[0].toUpperCase() + option.slice(1)}
    </Button>
  {/each}
</ButtonGroup>

Keyboard

Key
Enter, Space Presses the button. A link opens on Enter.
Tab Moves past it. A disabled, busy or hidden button isn't reached.

Accessibility

  • A native <button>, or an <a> with href: the role, focus and keys are the browser's.
  • loading sets aria-busy="true" and disables it. The spinner is hidden from screen readers, so the label is what's read.
  • A group is role="group", named by label.
  • A toggle in a group says whether it's on with aria-pressed, which goes to the button.

API

Button

Prop Type Default Description
variant "default" | "primary" | "ghost" | "danger" "default" How it looks.
size "md" | "sm" "md" sm for dense places.
type "button" | "submit" | "reset" "button" A submit button in a Form is busy while it saves.
href string — Makes it a link. An app path goes through the router.
disabled boolean false
loading boolean false Busy: a spinner, aria-busy, and it can't be pressed.
can string — The ability it needs, such as customers.delete.
canMode "hide" | "disable" "hide" What a user without can sees.
confirm string — A question to ask first. It goes on only on yes.
confirmLabel string — The confirm dialog's button.
onclick (event) => void | Promise<void> — Runs on a press, after a yes.
class string "" Added to the button's classes.
children Snippet — The label.

Other attributes go to the <button> (or the <a>): title, aria-label, aria-pressed, form, target.

ButtonGroup

Prop Type Default Description
label string — The group's name, for a screen reader.
class string ""
children Snippet — The buttons.

Other attributes go to the group's <div>.