Duck-UIDuck-UI

API Reference

Complete API reference for @duck_ui/embed components, hooks, and types

@duck_ui/embed API Reference

Complete API reference for the @duck_ui/embed package.

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

Table of Contents


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. Composes Chart, DataTable, KPICard, and FilterBar into a themed dashboard.

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.

DashboardPanelProps

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)

Types

QueryResult

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

ColumnInfo

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

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'
PropertylightThemedarkTheme
background#ffffff#111827
textColor#374151#e5e7eb
primaryColor#2563eb#60a5fa
surfaceColor#f9fafb#1f2937
borderColor#e5e7eb#374151

On this page