Skip to content

Rich Editing (Lookup / External Editor / Tooltip)

This demo showcases the schema hooks that enable “rich editing” integrations:

  • Remote lookup (typeahead + label/value separation)
  • External editor delegation (Promise-based commit/cancel)
  • Async tooltips (sync or Promise)

Interactive Demo

How it works

Remote lookup

Configure a column with edit.lookup.fetchCandidates. Extable displays the candidate label, but stores a structured value containing the stable value.

ts
import type { LookupCandidate } from "@extable/core";

const fetchCandidates = async ({ query, signal }: { query: string; signal?: AbortSignal }): Promise<LookupCandidate[]> => {
  // Fetch from your API, respecting AbortSignal.
  // Return [{ label, value, meta? }, ...]
  // Note: Return all candidates even for empty query, so that candidates are displayed
  // when clicking a cell in selection mode.
  const q = query.trim().toLowerCase();
  const allUsers = [{ id: "u1", name: "Alice" }, ...];
  return allUsers
    .filter(u => !q || u.name.toLowerCase().includes(q))
    .map(u => ({ label: u.name, value: u.id }));
};

const schema = {
  columns: [
    {
      key: "assignee",
      type: "string",
      edit: {
        lookup: {
          fetchCandidates,
        },
      },
    },
  ],
};

External editor delegation

Configure edit.externalEditor.open. When the user enters edit mode on that column, Extable calls your hook and waits for the Promise.

ts
const schema = {
  columns: [
    {
      key: "details",
      type: "string",
      edit: {
        externalEditor: {
          open: async ({ rowId, colKey, currentValue }) => {
            // Open your modal / rich editor UI.
            // Return { kind: "commit", value } or { kind: "cancel" }.
            return { kind: "cancel" };
          },
        },
      },
    },
  ],
};

Tooltip text (async)

Configure tooltip.getText. The hook may return string | null or Promise<string | null>.

ts
const schema = {
  columns: [
    {
      key: "assignee",
      type: "string",
      tooltip: {
        getText: async ({ currentValue, signal }) => {
          // Fetch details for hover display.
          return currentValue ? String(currentValue) : null;
        },
      },
    },
  ],
};

Released under the Apache 2.0 License