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
UI components (`@elyra/ui`)

UI components (@elyra/ui)

Desktop components for Svelte 5 that know they're in an Elyra app. They check what the user may do, show Laravel's validation errors under the fields they belong to, ask through the runtime's dialog before what can't be undone, and run a live.* list. They're themed by the design tokens, work from the keyboard and carry ARIA. (RFC 0012)

Examples
<script>
  import { ValidationError } from "@elyra/runtime";
  import { Button, Field, Form, Input, Select } from "@elyra/ui";

  let customer = $state({ name: "Ada Lovelace", email: "ada@", country: "Norway" });
  let saved = $state(false);

  // In an app this is `api.customers_store(customer)`: Laravel's 422 (or a
  // command's ValidationErrors) is thrown the same way.
  async function save() {
    saved = false;
    await new Promise((resolve) => setTimeout(resolve, 600));
    if (!customer.email.includes(".")) {
      throw new ValidationError("customers_store", { email: ["The email must be a valid email address."] }, "{}");
    }
    saved = true;
  }
</script>

<Form onsubmit={save}>
  <Field name="name" label="Name" required>
    <Input bind:value={customer.name} />
  </Field>
  <Field name="email" label="Email" required description="Invoices go here.">
    <Input type="email" bind:value={customer.email} />
  </Field>
  <Field name="country" label="Country">
    <Select bind:value={customer.country} options={["Denmark", "Finland", "Norway", "Sweden"]} />
  </Field>
  <Button type="submit" variant="primary">{saved ? "Saved" : "Save customer"}</Button>
</Form>

Save it as it is: the email is wrong on purpose, and the message lands under its field. That's Laravel's 422, or a command's ValidationErrors, thrown by the save and caught by the Form.

Install

rata new adds the package. The app depends on the release's elyra-ui-<version>.tgz, or on the checkout's ui/ with --elyra. It imports the tokens in main.js, and its Vite config keeps one copy of svelte and @elyra/runtime. An app made before 0.21 adds the same three:

"@elyra/ui": "https://github.com/kwhorne/elyra-framework/releases/download/v0.27.0/elyra-ui-0.27.0.tgz"
// app/src/main.js: the tokens first, then the app's own CSS
import "@elyra/ui/tokens.css";
import "./app.css";
// app/vite.config.js
resolve: { dedupe: ["svelte", "@elyra/runtime"] },

The package is Svelte source with no build step of its own. Its peers are svelte 5 and @elyra/runtime 0.20 or later.

What they know about the app

The user's abilities can="customers.delete" hides a Button, a MenuItem, a NavItem or a tab from a user without the ability. On a button, canMode="disable" shows it disabled instead. The abilities come from Laravel (RFC 0010), or from the app's own grants without a backend. The server still decides.
Validation A Form catches what its onsubmit throws. Laravel's 422, or a command's ValidationErrors, puts each message under its Field, and the rest at the top.
Confirming confirm="Delete Ada?" on a Button asks in the runtime's dialog, the same one confirm() opens.
Live lists A Table runs a live.* page. Its search, sort and page go into the query, so the command runs again and the list stays current.
The router href="/customers/7" on a Button, and a NavItem's path, go through the app's router. A NavItem knows when its page is open.
What the app is doing The StatusBar shows offline since when, the outbox, uploads and downloads, and the app's assistant. Its outbox counts open the OutboxDrawer, where the user keeps, retries or discards what Laravel refused.

The components

Actions Button and ButtonGroup, Dropdown and MenuItem
Forms Form and Field, Input and Textarea, Select, Combobox, DatePicker, Checkbox, Switch, RadioGroup, FileField
Overlays Modal and Drawer, Popover, Tooltip
Data Table and Pagination, Badge, Avatar, Presence, Kbd
Layout AppShell, Sidebar, NavItem and Toolbar, StatusBar, SplitPane, Tabs, Card, Separator
Feedback Callout, OutboxDrawer, Empty, Spinner and Skeleton

How they're used

  • Import from the package: import { Button, Table } from "@elyra/ui".
  • Values are bound: bind:value on the inputs, bind:checked on a Checkbox or Switch, bind:open on the overlays, bind:query on a Table, bind:page on Pagination.
  • Snippets fill the parts: a Card's actions and footer, a Table's cell(row, column) and actions(row), a Tab's panel(id).
  • Every component takes class, added to its outer element. Most pass any other attribute to the element they're built on. Each page's API says which element that is.
  • Your own styles use the tokens, so they follow the theme with everything else. The components add no colours of their own.
  • Words: Table and Pagination take labels for theirs. The few others (Select's "Search…", Combobox's "Searching…", the StatusBar's, the close buttons' names) are English for now. To change them, copy the component into the app (below).

Generated screens

rata make:resource Customer --view writes the list and the form on these components: a Table over the live index command, and a Card with a Form and a Field per field. The delete is behind a confirm, and the buttons are behind the user's abilities. They're the app's files from then on.

Owning a component

When a component needs more than its props, copy it into the app:

$ rata make:ui Table
wrote app/src/lib/ui/Table.svelte

The copy comes from the @elyra/ui the app has installed, so it matches the rest of the package. It starts with a line saying which version. Its imports of the other components and of the package's internals point back at @elyra/ui, so a copied Field still gets its errors from @elyra/ui's Form. Import your copy where you want it instead of the package's; the other views keep the package's.

The file is the app's. rata won't overwrite it (--force replaces it), and upgrading @elyra/ui doesn't touch it. rata make:ui --list shows what can be copied.

This reference

These pages are docs/ui/ in the repository. npm run docs in ui/ serves them with every example running, in both themes. The examples are ui/docs/examples/, and the tests compile and mount each one. They also hold every page's props table to the component's own props.

Related