Duck-UIDuck-UI

API Reference

Complete API reference for @duck_ui/core, @duck_ui/embed, @duck_ui/elements, and CDN usage

API Reference

Complete API reference for all Duck-UI packages.


Table of Contents


Core Package

@duck_ui/core is the framework-agnostic engine. It manages DuckDB-WASM, executes queries, handles filter injection, and provides chart data factories.

bun add @duck_ui/core @duckdb/duckdb-wasm

DuckUI Class

The imperative entry point for all Duck-UI functionality.

import { DuckUI } from '@duck_ui/core'

Constructor

const ui = new DuckUI()

Methods

MethodSignatureDescription
init(data: Record<string, DataInput>) => Promise<void>Boot DuckDB-WASM, load data into tables
query(sql: string) => Promise<QueryResult>Execute SQL against in-browser DuckDB
setFilter(column: string, value: FilterValue) => voidSet a global filter
clearFilters() => voidClear all active filters
getSchema(tableName: string) => Promise<TableSchema | null>Inspect table columns and types
destroy() => Promise<void>Tear down DuckDB, release memory

Usage

import { DuckUI } from '@duck_ui/core'

const ui = new DuckUI()
await ui.init({
  orders: [
    { id: 1, product: 'Widget', total: 99.50 },
    { id: 2, product: 'Gadget', total: 149.00 },
  ],
  sales: { url: '/data/sales.parquet', format: 'parquet' },
})

const result = await ui.query('SELECT product, SUM(total) AS rev FROM orders GROUP BY 1')
console.log(result.rows) // [{ product: 'Widget', rev: 99.5 }, ...]

ui.setFilter('product', 'Widget')
const filtered = await ui.query('SELECT * FROM orders')
// Automatically applies WHERE "product" = 'Widget'

const schema = await ui.getSchema('orders')
// { tableName: 'orders', columns: [{ name: 'id', type: 'INTEGER', nullable: true }, ...] }

ui.clearFilters()
await ui.destroy()

Chart Factories

Pure functions that transform QueryResult into chart-ready data structures. No DOM dependency.

import {
  toBarData,
  toLineData,
  toAreaData,
  toScatterData,
  toPieData,
  toSparklineData,
} from '@duck_ui/core'
FactoryInputOutput
toBarData(result)QueryResult{ labels: string[], series: { name: string, values: number[] }[] }
toLineData(result)QueryResult{ x: number[], series: { name: string, values: number[] }[] }
toAreaData(result)QueryResultSame as toLineData (rendered with fill)
toScatterData(result)QueryResult{ points: { x: number, y: number, label?: string }[] }
toPieData(result)QueryResult{ slices: { label: string, value: number }[] }
toSparklineData(result)QueryResultnumber[]

First column becomes labels/x-values, remaining columns become series. These factories are what @duck_ui/embed and @duck_ui/elements use internally.

Engine Exports

Lower-level building blocks for advanced use cases:

import {
  DuckDBManager,
  ConnectionPool,
  QueryExecutor,
  QueryCache,
  FilterInjector,
} from '@duck_ui/core'
ExportDescription
DuckDBManagerManages DuckDB-WASM lifecycle (init, worker, bundles)
ConnectionPoolConnection pool (default 4 concurrent connections)
QueryExecutorExecutes SQL, coerces result types
QueryCacheLRU query result cache
FilterInjectorInjects WHERE clauses from active filters

React Package

@duck_ui/embed provides React components and hooks that wrap @duck_ui/core.

bun add @duck_ui/embed @duckdb/duckdb-wasm

Provider

DuckUIProvider

Initializes DuckDB-WASM, loads data into tables, and provides context to all child components.

import { DuckUIProvider } from '@duck_ui/embed'

DuckUIProviderProps

PropTypeDefaultDescription
dataRecord<string, DataInput>requiredData tables. Key = DuckDB table name, value = data source.
themePartial<DuckTheme>lightThemeTheme overrides (shallow-merged with defaults)
onReady() => void--Called when engine is ready and all data is loaded
onError(error: Error) => void--Called on initialization or data loading error

DataInput

The value type for each entry in the data prop. The key becomes the DuckDB table name.

type DataInput =
  | Record<string, unknown>[]                              // Array of objects -> table
  | { url: string; format?: 'csv' | 'json' | 'parquet' }  // Remote file
  | { fetch: () => Promise<Record<string, unknown>[]> }    // Async callback
  | File                                                    // Browser File object
VariantDescriptionExample
Array of objectsData already in memory, loaded directly{ orders: [{ id: 1, total: 99 }] }
URL objectFetches remote file. Parquet uses HTTP range requests.{ sales: { url: '/data/sales.parquet' } }
Fetch callbackYou call your own API, return rows{ users: { fetch: () => api.getUsers() } }
FileBrowser File API (drag & drop, file input){ upload: fileFromInput }

Usage

<DuckUIProvider
  data={{
    orders: [
      { id: 1, product: 'Widget', total: 99.50 },
      { id: 2, product: 'Gadget', total: 149.00 },
    ],
    sales: { url: '/data/sales.parquet', format: 'parquet' },
    users: { fetch: () => fetch('/api/users').then(r => r.json()) },
  }}
  theme={{ primaryColor: '#4f46e5' }}
  onReady={() => console.log('Ready')}
  onError={(err) => console.error(err)}
>
  {children}
</DuckUIProvider>

Hooks

useDuckUI()

function useDuckUI(): { query: (sql: string) => Promise<QueryResult>; status: Status }

Public hook for executing SQL queries and checking engine status.

ReturnTypeDescription
query(sql: string) => Promise<QueryResult>Execute any SQL against the in-browser DuckDB
status'idle' | 'loading' | 'ready' | 'error'Engine initialization status
import { useDuckUI } from '@duck_ui/embed'

function MyComponent() {
  const { query, status } = useDuckUI()

  if (status !== 'ready') return <p>Loading...</p>

  const handleClick = async () => {
    const result = await query('SELECT count(*) as n FROM orders')
    console.log(result.rows) // [{ n: 42 }]
  }

  return <button onClick={handleClick}>Count orders</button>
}

useTheme()

function useTheme(): DuckTheme

Returns the merged theme object (defaults + user overrides).

import { useTheme } from '@duck_ui/embed'

const theme = useTheme()
// theme.primaryColor, theme.background, theme.palette, etc.

Components

Chart

SQL-driven chart component. Supports line, bar, area, and scatter types.

import { Chart } from '@duck_ui/embed'
ChartProps
PropTypeDefaultDescription
sqlstringrequiredSQL query to execute
type'line' | 'bar' | 'area' | 'scatter''line'Chart type
heightnumber300Chart height in pixels
widthnumberauto (fills container)Chart width in pixels
titlestring--Chart title
colorsstring[]theme paletteSeries colors
legendbooleantrueShow legend
axes{ x?: AxisOptions; y?: AxisOptions }--Axis labels and formatting
tooltipboolean | TooltipOptionstrueTooltip config
classNamestring--CSS class
tableNamestring--Table name for filter injection
onPointClick(seriesIdx, dataIdx, value) => void--Point click handler
onRangeSelect(min, max) => void--Range selection handler

Data transformation: First column -> x-axis, remaining columns -> y-series.

<Chart
  sql="SELECT month, SUM(revenue) AS rev FROM sales GROUP BY 1 ORDER BY 1"
  type="bar"
  height={350}
  axes={{ y: { format: 'currency' } }}
/>

DataTable

SQL-driven paginated table with sorting and column resizing.

import { DataTable } from '@duck_ui/embed'
DataTableProps
PropTypeDefaultDescription
sqlstringrequiredSQL query
pageSizenumber25Rows per page
sortablebooleantrueEnable column sorting
resizablebooleantrueEnable column resizing
stripedbooleantrueAlternate row colors
maxHeightnumber | string--Max scroll container height
classNamestring--CSS class
tableNamestring--Table name for filter injection

Pagination and sorting happen at the SQL level -- only the visible page is loaded.

<DataTable sql="SELECT * FROM orders" pageSize={50} sortable />

KPICard

Single-value metric card with optional comparison and sparkline.

import { KPICard } from '@duck_ui/embed'
KPICardProps
PropTypeDefaultDescription
sqlstringrequiredQuery returning a single value (first column, first row)
labelstringrequiredKPI label
format'currency' | 'percent' | 'number' | 'compact' | (v: number) => string--Value formatter
currencystring'USD'Currency code (when format is 'currency')
compareSqlstring--Previous period value for % change
compareLabelstring--Label for comparison (e.g., "vs 2024")
sparklineSqlstring--Time series query for inline trend line
classNamestring--CSS class
tableNamestring--Table name for filter injection
<KPICard
  sql="SELECT SUM(total) AS value FROM orders"
  label="Total Revenue"
  format="currency"
  currency="USD"
  compareSql="SELECT SUM(total) AS value FROM orders WHERE year = 2024"
  compareLabel="vs 2024"
  sparklineSql="SELECT month, SUM(total) FROM orders GROUP BY 1 ORDER BY 1"
/>

ExportButton

CSV/JSON export button.

import { ExportButton } from '@duck_ui/embed'
ExportButtonProps
PropTypeDefaultDescription
dataQueryResult | nullrequiredData to export
format'csv' | 'json''csv'Export format
fileNamestring'export'Download file name (without extension)
labelstring'Export'Button label
classNamestring--CSS class

Disabled when data is null or has zero rows.

const { data } = useQuery('SELECT * FROM sales')
<ExportButton data={data} format="csv" fileName="sales-report" />

Layout

Dashboard

CSS Grid layout container with responsive breakpoints.

import { Dashboard } from '@duck_ui/embed'
DashboardProps
PropTypeDefaultDescription
childrenReactNoderequiredDashboard.Panel children
columns1 | 2 | 3 | 42Grid columns at full width
gapnumber16Gap between panels (px)
paddingnumber24Container padding (px)
classNamestring--CSS class
Dashboard.Panel

Grid item wrapper.

PropTypeDefaultDescription
childrenReactNoderequiredPanel content
spannumber1Column span
rowSpannumber1Row span
classNamestring--CSS class

Responsive breakpoints (auto-reduces columns based on container width):

  • < 480px -> 1 column
  • < 768px -> max 2 columns
  • < 1024px -> max 3 columns
  • >= 1024px -> columns as specified
<DuckUIProvider data={{ orders }}>
  <Dashboard columns={3} gap={16}>
    <Dashboard.Panel span={2}>
      <FilterBar auto="orders" />
    </Dashboard.Panel>
    <Dashboard.Panel>
      <KPICard sql="SELECT count(*) as value FROM orders" label="Orders" />
    </Dashboard.Panel>
    <Dashboard.Panel span={2}>
      <Chart sql="SELECT status, count(*) FROM orders GROUP BY 1" type="bar" />
    </Dashboard.Panel>
    <Dashboard.Panel>
      <Chart sql="SELECT date, sum(total) FROM orders GROUP BY 1" type="line" />
    </Dashboard.Panel>
    <Dashboard.Panel span={3}>
      <DataTable sql="SELECT * FROM orders" pageSize={20} sortable />
    </Dashboard.Panel>
  </Dashboard>
</DuckUIProvider>

Filters

All filter components integrate with the DuckUIProvider filter system. When a filter value changes, all queries automatically re-execute with new WHERE clauses injected.

FilterBar

Container for filter components. Shows "Clear filters" button when any filter is active.

import { FilterBar } from '@duck_ui/embed'
FilterBarProps
PropTypeDefaultDescription
filtersFilterConfig[]--Manual filter configuration
autostring--Auto-detect filters from table schema
sourcestring--Table to read distinct values from
classNamestring--CSS class

Auto mode: Pass a table name and filters are detected from column types.

Manual mode: Pass an array of FilterConfig objects.

// Auto mode
<FilterBar auto="orders" />

// Manual mode
<FilterBar filters={[
  { column: 'status', type: 'select' },
  { column: 'total', type: 'range', min: 0, max: 1000 },
  { column: 'created_at', type: 'daterange' },
]} source="orders" />
FilterConfig
interface FilterConfig {
  column: string
  type: 'select' | 'multiselect' | 'range' | 'daterange'
  label?: string
  min?: number        // For range
  max?: number        // For range
  step?: number       // For range
  options?: string[]  // For select (explicit options)
}

SelectFilter

Searchable single-select dropdown with keyboard navigation.

PropTypeDefaultDescription
columnstringrequiredColumn to filter
optionsstring[]--Explicit options
sourcestring--Table to query DISTINCT values from
labelstring--Display label
placeholderstring'All'Placeholder text

MultiSelectFilter

Toggle buttons for multi-select.

PropTypeDefaultDescription
columnstringrequiredColumn to filter
optionsstring[]requiredAvailable options
labelstring--Display label

RangeFilter

Dual-thumb numeric range slider.

PropTypeDefaultDescription
columnstringrequiredColumn to filter
minnumberrequiredRange minimum
maxnumberrequiredRange maximum
stepnumber1Step increment
labelstring--Display label

DateRangeFilter

Calendar-based date range picker.

PropTypeDefaultDescription
columnstringrequiredColumn to filter
labelstring--Display label

Filter SQL Generation

FilterValueGenerated SQL
'North'"col" = 'North'
42"col" = 42
true"col" = true
['A', 'B']"col" IN ('A', 'B')
{ min: 10, max: 100 }"col" >= 10 AND "col" <= 100
{ start: '2024-01-01', end: '2024-12-31' }"col" BETWEEN '2024-01-01' AND '2024-12-31'
null(filter cleared)

Web Components Package

@duck_ui/elements provides Custom Elements that wrap @duck_ui/core. They work in any HTML page or framework.

bun add @duck_ui/elements

All elements are registered automatically on import. Attributes use kebab-case.

<duck-provider>

Root element. Initializes DuckDB-WASM and provides context to child elements.

AttributeTypeDefaultDescription
theme'light' | 'dark''light'Built-in theme
srcstring--URL to a data file (CSV, JSON, or Parquet)
tablestring--Table name for the src data
format'csv' | 'json' | 'parquet'auto-detectFile format for src

For multiple tables, nest multiple <duck-provider> elements or use the imperative DuckUI class from @duck_ui/core.

<duck-provider src="/data/orders.json" table="orders" theme="dark">
  <!-- child elements -->
</duck-provider>

<duck-chart>

SQL-driven chart.

AttributeTypeDefaultDescription
sqlstringrequiredSQL query
type'line' | 'bar' | 'area' | 'scatter''line'Chart type
heightstring (px)'300'Chart height
widthstring (px)autoChart width
titlestring--Chart title
<duck-chart
  sql="SELECT product, SUM(total) AS revenue FROM orders GROUP BY 1"
  type="bar"
  height="350"
  title="Revenue by Product"
></duck-chart>

<duck-table>

SQL-driven paginated table.

AttributeTypeDefaultDescription
sqlstringrequiredSQL query
page-sizestring (number)'25'Rows per page
sortableboolean attr--Enable column sorting (present = true)
stripedboolean attr--Alternate row colors
max-heightstring--Max scroll height (e.g., '400px')
<duck-table sql="SELECT * FROM orders" page-size="50" sortable striped></duck-table>

<duck-kpi>

Single-value metric with optional comparison and sparkline.

AttributeTypeDefaultDescription
sqlstringrequiredQuery returning a single value
labelstringrequiredKPI label
format'currency' | 'percent' | 'number' | 'compact'--Value formatter
currencystring'USD'Currency code
compare-sqlstring--Previous period value for % change
sparkline-sqlstring--Time series query for inline trend
<duck-kpi
  sql="SELECT SUM(total) AS value FROM orders"
  label="Total Revenue"
  format="currency"
  compare-sql="SELECT SUM(total) AS value FROM orders WHERE year = 2024"
></duck-kpi>

<duck-dashboard> + <duck-panel>

CSS Grid layout.

<duck-dashboard>

AttributeTypeDefaultDescription
columnsstring (number)'2'Grid columns
gapstring (px)'16'Gap between panels
paddingstring (px)'24'Container padding

<duck-panel>

AttributeTypeDefaultDescription
spanstring (number)'1'Column span
row-spanstring (number)'1'Row span
<duck-dashboard columns="3" gap="16">
  <duck-panel span="2">
    <duck-filter-bar auto source="orders"></duck-filter-bar>
  </duck-panel>
  <duck-panel>
    <duck-kpi sql="SELECT count(*) as value FROM orders" label="Orders"></duck-kpi>
  </duck-panel>
  <duck-panel span="3">
    <duck-table sql="SELECT * FROM orders" page-size="20" sortable></duck-table>
  </duck-panel>
</duck-dashboard>

<duck-filter-bar>

Auto-detecting or manual filter container.

AttributeTypeDefaultDescription
autoboolean attr--Auto-detect filters from table schema (present = true)
sourcestring--Table name for distinct values

Individual Filter Elements

<duck-select-filter>

AttributeTypeDefaultDescription
columnstringrequiredColumn to filter
sourcestring--Table to query DISTINCT values from
labelstring--Display label

<duck-range-filter>

AttributeTypeDefaultDescription
columnstringrequiredColumn to filter
minstring (number)requiredRange minimum
maxstring (number)requiredRange maximum
stepstring (number)'1'Step increment
labelstring--Display label

<duck-date-filter>

AttributeTypeDefaultDescription
columnstringrequiredColumn to filter
labelstring--Display label

<duck-export>

Export button for downloading query results.

AttributeTypeDefaultDescription
sqlstringrequiredSQL query to export
format'csv' | 'json''csv'Export format
file-namestring'export'Download file name (without extension)
labelstring'Export'Button label
<duck-export sql="SELECT * FROM orders" format="csv" file-name="orders-report" label="Download CSV"></duck-export>

Events

All events are CustomEvent instances dispatched on <duck-provider>:

EventdetailDescription
duck-ready{}Engine initialized and data loaded
duck-error{ error: Error }Initialization or query error
duck-filter-change{ filters: Record<string, FilterValue> }A filter was set or cleared
const provider = document.querySelector('duck-provider')

provider.addEventListener('duck-ready', () => {
  console.log('Duck-UI is ready')
})

provider.addEventListener('duck-filter-change', (e) => {
  console.log('Active filters:', e.detail.filters)
})

CSS Custom Properties (Theming)

Style Web Components with CSS custom properties on <duck-provider> or any ancestor:

PropertyDefault (light)Description
--duck-bg#ffffffBackground color
--duck-text#374151Text color
--duck-primary#2563ebPrimary / accent color
--duck-surface#f9fafbSurface / card background
--duck-border#e5e7ebBorder color
--duck-grid#e5e7ebChart grid lines
--duck-hover#f3f4f6Hover state background
--duck-muted#9ca3afMuted text color
--duck-error#ef4444Error color
--duck-success#22c55eSuccess color
duck-provider {
  --duck-bg: #1a1a2e;
  --duck-text: #e0e0e0;
  --duck-primary: #00d4ff;
  --duck-surface: #16213e;
  --duck-border: #374151;
}

CDN Package

@duck_ui/cdn bundles @duck_ui/core + @duck_ui/elements + @duckdb/duckdb-wasm into a single IIFE script. No bundler, no npm.

Script Tag

<script src="https://unpkg.com/@duck_ui/cdn/dist/duck-ui.min.js"></script>

This does two things:

  1. Registers all Custom Elements (<duck-provider>, <duck-chart>, etc.) -- use them in HTML immediately.
  2. Exposes window.DuckUI -- the imperative DuckUI class for programmatic use.

Full Example

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/@duck_ui/cdn/dist/duck-ui.min.js"></script>
</head>
<body>
  <duck-provider src="/data/orders.json" table="orders" theme="dark">
    <duck-dashboard columns="2">
      <duck-panel>
        <duck-kpi
          sql="SELECT SUM(total) AS value FROM orders"
          label="Revenue"
          format="currency"
        ></duck-kpi>
      </duck-panel>
      <duck-panel>
        <duck-chart
          sql="SELECT status, count(*) AS n FROM orders GROUP BY 1"
          type="bar"
          height="300"
        ></duck-chart>
      </duck-panel>
      <duck-panel span="2">
        <duck-table sql="SELECT * FROM orders" page-size="25" sortable></duck-table>
      </duck-panel>
    </duck-dashboard>
  </duck-provider>
</body>
</html>

Imperative Use via CDN

<script src="https://unpkg.com/@duck_ui/cdn/dist/duck-ui.min.js"></script>
<script>
  const ui = new DuckUI()
  ui.init({
    orders: [
      { id: 1, product: 'Widget', total: 99.50 },
      { id: 2, product: 'Gadget', total: 149.00 },
    ],
  }).then(async () => {
    const result = await ui.query('SELECT * FROM orders')
    console.log(result.rows)
  })
</script>

Types

QueryResult

interface QueryResult {
  rows: Record<string, unknown>[]
  columns: ColumnInfo[]
  rowCount: number
  executionTime: number  // milliseconds
}

ColumnInfo

interface ColumnInfo {
  name: string
  type: string
  nullable: boolean
}

TableSchema

interface TableSchema {
  tableName: string
  columns: ColumnInfo[]
}

FilterValue

type FilterValue =
  | string
  | number
  | boolean
  | string[]
  | number[]
  | { min: number; max: number }
  | { start: string; end: string }
  | null

ChartTheme

interface ChartTheme {
  background: string
  textColor: string
  gridColor: string
  axisColor: string
  palette: string[]
  fontFamily: string
  fontSize: number
}

DuckTheme

Extends ChartTheme with component-level styling:

interface DuckTheme extends ChartTheme {
  surfaceColor: string
  borderColor: string
  hoverColor: string
  primaryColor: string
  errorColor: string
  errorBgColor: string
  mutedTextColor: string
  stripeColor: string
  successColor: string
  successBgColor: string
  dangerColor: string
  dangerBgColor: string
}

AxisOptions

interface AxisOptions {
  label?: string
  format?: 'number' | 'currency' | 'percent' | 'date' | ((value: number) => string)
}

Built-in Themes

import { lightTheme, darkTheme } from '@duck_ui/embed'
// or
import { lightTheme, darkTheme } from '@duck_ui/core'
PropertylightThemedarkTheme
background#ffffff#111827
textColor#374151#e5e7eb
primaryColor#2563eb#60a5fa
surfaceColor#f9fafb#1f2937
borderColor#e5e7eb#374151

On this page