AdaptTable for Unstyled

AI table assistant in Unstyled Angular

This demo mounts a real Unstyled Angular table and its Unstyled assistant. Start with scripted sorting, questions and approved edits, or connect your HTTP backend for free-form AI requests. The scripted mode needs no model or API key.

A question filters the table only after you answer. A proposed edit waits for your approval in the assistant, the table or a dialog; an approved write updates the host's data and its status line. Rejecting leaves the data unchanged, and the conversation records the execution result.

tableAgent and injectTableAssistant from @adapttable/ai-angular share the mounted table's session. The snippet below shows a minimal local sorting transport; the demo also includes questions and governed edits. JSON, OpenAI, HTTP, MCP, MCP Apps, WebMCP, AG-UI and AI SDK helpers can use the same session in your application.

The assistant, question choices and approval controls are native HTML. Start with the local script or connect your HTTP backend. The host status line records approved writes, and the approval-surface selector chooses assistant, table or dialog review.

The code

import type { AgentSession, AssistantTransport } from "@adapttable/ai";
import { injectTableAssistant, tableAgent } from "@adapttable/ai-angular";
import type { ColumnDef, TableAssistantProps } from "@adapttable/angular";
import { AdaptDataTable } from "@adapttable/angular-unstyled";
import { AdaptTableAssistant } from "@adapttable/angular-unstyled/assistant";
import { Component, computed, signal } from "@angular/core";

interface AgentPerson { id: string; name: string; salary: number }

// A minimal local transport: no model, endpoint or API key.
const transport: AssistantTransport = {
  send: async ({ session, text, signal }) => {
    if (!text.toLowerCase().includes("sort")) {
      return { text: "Try: sort salaries highest first." };
    }
    const key = "view.setSort";
    const result = await session.execute(
      key,
      { key: "salary", dir: "desc" },
      session.manifest().viewRevision,
      crypto.randomUUID(),
      signal
    );
    return {
      text: result.ok ? "Highest salary first." : "The sort was not applied.",
      keys: [key],
      results: [result],
    };
  },
};

@Component({
  selector: "app-people-assistant",
  imports: [AdaptDataTable, AdaptTableAssistant],
  template: `
    <adapt-data-table
      [data]="rows" [columns]="columns" [rowKey]="rowKey"
      [features]="features" [urlSync]="false"
    />
    <adapt-table-assistant [props]="props()" />
  `,
})
export class PeopleAssistant {
  readonly rows: readonly AgentPerson[] = [
    { id: "ada", name: "Ada Lovelace", salary: 120 },
    { id: "grace", name: "Grace Hopper", salary: 140 },
  ];
  readonly columns: readonly ColumnDef<AgentPerson>[] = [
    { key: "name", header: "Person" },
    { key: "salary", header: "Salary", sortable: true },
  ];
  readonly rowKey = (row: AgentPerson) => row.id;
  readonly session = signal<AgentSession | undefined>(undefined);
  readonly open = signal(false);
  readonly assistant = injectTableAssistant(computed(() => ({
    session: this.session(), transport,
  })));
  readonly props = computed((): TableAssistantProps => ({
    assistant: this.assistant(),
    open: this.open(),
    onOpenChange: (open) => this.open.set(open),
    presentation: "floating",
  }));
  readonly features = [tableAgent({
    tableId: "people", approval: "never",
    columns: { salary: { type: "number", sortable: true } },
    bridge: { attach: (session) => this.session.set(session) },
  })];
}

Install

pnpm add @adapttable/angular-unstyled @adapttable/angular @adapttable/core

The same feature in the other kits

More Unstyled features

Reference: ai-http, ai-integrations, ai, agent-capabilities. More of this kit: AdaptTable for Unstyled, or the live demo.