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
Elyra
Vue 3 + Inertia client

Vue 3 + Inertia client

A thin Vue 3 wrapper around the headless engine. Talks the same protocol as the Livewire and Svelte clients over fetch, and shares the Tailwind v4 theme.

Install

composer require elyra/datagrid-js

The Vue client, headless core and theme ship in the elyra/datagrid-js Composer package (same token as the server — no npm registry). Alias the @elyra/* specifiers to vendor/elyra/datagrid-js/dist/* in vite.config.ts — see Installation.

// resources/js/app.ts
import '@elyra/datagrid-theme/theme.css';
import '@elyra/datagrid-theme/accents.css';
import '@elyra/datagrid-theme/grid.css';

Set up the endpoints and CSRF as in Inertia integration.

Component

<script setup lang="ts">
import { DataGrid, laravelFetch } from '@elyra/datagrid-vue';
import type { GridResponse, GridMutation, GridMutationResult } from '@elyra/datagrid-vue';

const props = defineProps<{ initial?: GridResponse }>();

const mutate = async (m: GridMutation): Promise<GridMutationResult> =>
    (await fetch('/api/sales/mutate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
        body: JSON.stringify(m),
    })).json();

const options = {
    key: 'id',
    columns: [
        { field: 'sku', header: 'SKU', frozen: true, cell: { type: 'link' as const, href: '/orders/{id}' } },
        { field: 'region', header: 'Region' },
        { field: 'status', header: 'Status', editable: true, editor: 'select' as const,
          options: [{ value: 'paid', label: 'paid' }, { value: 'pending', label: 'pending' }],
          badges: { pending: 1, paid: 2, shipped: 3, delivered: 4, returned: 5 } },
        { field: 'revenue', header: 'Revenue', type: 'number' as const, align: 'right' as const,
          editable: true, editor: 'number' as const, cell: { type: 'currency' as const, symbol: 'kr ', decimals: 2 } },
    ],
    fetch: laravelFetch('/api/sales/grid'),
    exportUrl: '/api/sales/export',
    initialData: props.initial,
    persistKey: 'sales',
    selection: { mode: 'multiple' as const },
    grouping: { aggregates: [{ field: 'revenue', fn: 'sum' as const, as: 'sum_revenue' }] },
    search: true,
    editing: { mode: 'slideover' as const, mutate },
    columnOps: true,
};
</script>

<template>
    <DataGrid :options="options" heading="Sales" accent="emerald" />
</template>

Props

Prop Type Default Purpose
options GridOptions — The grid config (see Client core API).
theme string '' '' (app) or a preset like tokyo-night.
accent string '' '' (app) or a Flux-style accent.
heading string Data Toolbar title.
height number 480 Viewport height (virtual scroll mode).
messages Partial<Messages> — UI string overrides (i18n).

Natural-language filtering

Pass an ask function in the options to add an "ask in plain language" box to the toolbar. It POSTs to an endpoint that calls GridDefinition::ask() and returns the translated filter; the client applies it and refetches.

const options = {
  // ...
  ask: async (query: string) => {
    const res = await fetch('/api/sales/ask', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
      body: JSON.stringify({ q: query }),
    });
    return (await res.json()).filter;   // FilterGroup | null
  },
};
Route::post('/api/sales/ask', fn (Request $r) =>
    response()->json(['filter' => salesGrid()->ask((string) $r->input('q'))]));

Omit ask to hide the box. Full guide: Natural-language filtering.

The composable

Prefer full control? Use useGrid directly and build your own markup:

import { useGrid } from '@elyra/datagrid-vue';

const { grid, state } = useGrid(options);
// state.value.data.rows, grid.toggleSort('revenue'), grid.setPageSize(50), ...

state is a shallowRef<GridState> kept in sync with the engine. Every method on grid is documented in the Client core API.

TypeScript

All protocol and option types are re-exported from @elyra/datagrid-vue (GridOptions, ColumnDef, GridResponse, GridMutation, Messages, …).

Pivot

For a cross-tab over the same source — dimensions on two axes, with subtotals and margins — this client also ships DataPivot from @elyra/datagrid-vue. See Pivot.