To create an interactive data table in Kino, you must implement the Kino.Table behaviour in a module. This module acts as the data provider, handling state initialization, data fetching, and optional export/update logic. The Kino.Table module handles the UI and orchestration, while your module manages the actual data lifecycle.
Required Callbacks
init(init_arg): Initializes the server state. Returns {:ok, info(), state()}.get_data(rows_spec(), state()): Fetches the data for the current view. Returns {:ok, %{columns: list(column()), data: {:columns | :rows, list(list(String.t()))}, total_rows: non_neg_integer() | nil}, state()}.
Optional Callbacks
export_data(rows_spec(), state(), format): Handles data export (e.g., to Markdown or CSV). Returns {:ok, %{data: binary(), extension: String.t(), type: String.t()}}.on_update(update_arg, state): Responds to external updates via Kino.Table.update/2. Returns {:ok, state()}.
Data Structures
info()
Used to configure the table's capabilities and appearance:
%{
:name => "My Table",
:features => [:pagination, :sorting, :export],
:num_rows => 50
}
:features: A list of supported features: :export, :refetch, :pagination, :sorting, :relocate, :actions.:export: If provided, a map containing :formats (list of strings).:num_rows: Sets the default number of rows per page.
column()
Defines the structure of a table column:
%{
:key => :id,
:label => "ID",
:type => "number",
:summary => %{"short" => "long"}
}
:type: Supported front-end types: "date", "list", "number", "struct", "text", "uri".
rows_spec()
Passed to get_data/2 and export_data/3 to describe the current view:
%{
:offset => 0,
:limit => 10,
:order => %{direction: :asc, key: :id},
:relocates => [%{from_index: 0, to_index: 1}]
}
defmodule MyTableProvider do
use Kino.Table
@impl true
def init(_init_arg) do
{:ok, %{name: "Users", features: [:pagination, :sorting]}, %{data: []}}
end
@impl true
def get_data(rows_spec, state) do
# Fetch data based on rows_spec (offset, limit, order)
{:ok, %{columns: columns, data: {:rows, rows}, total_rows: 100}, state}
end
end
# Usage
kino_table = Kino.Table.new(MyTableProvider, %{})