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) - React Package (
@duck_ui/embed) - Web Components Package (
@duck_ui/elements) - CDN Package (
@duck_ui/cdn) - Types
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-wasmDuckUI Class
The imperative entry point for all Duck-UI functionality.
import { DuckUI } from '@duck_ui/core'Constructor
const ui = new DuckUI()Methods
| Method | Signature | Description |
|---|---|---|
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) => void | Set a global filter |
clearFilters | () => void | Clear 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'| Factory | Input | Output |
|---|---|---|
toBarData(result) | QueryResult | { labels: string[], series: { name: string, values: number[] }[] } |
toLineData(result) | QueryResult | { x: number[], series: { name: string, values: number[] }[] } |
toAreaData(result) | QueryResult | Same 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) | QueryResult | number[] |
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'| Export | Description |
|---|---|
DuckDBManager | Manages DuckDB-WASM lifecycle (init, worker, bundles) |
ConnectionPool | Connection pool (default 4 concurrent connections) |
QueryExecutor | Executes SQL, coerces result types |
QueryCache | LRU query result cache |
FilterInjector | Injects 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-wasmProvider
DuckUIProvider
Initializes DuckDB-WASM, loads data into tables, and provides context to all child components.
import { DuckUIProvider } from '@duck_ui/embed'DuckUIProviderProps
| Prop | Type | Default | Description |
|---|---|---|---|
data | Record<string, DataInput> | required | Data tables. Key = DuckDB table name, value = data source. |
theme | Partial<DuckTheme> | lightTheme | Theme 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| Variant | Description | Example |
|---|---|---|
| Array of objects | Data already in memory, loaded directly | { orders: [{ id: 1, total: 99 }] } |
| URL object | Fetches remote file. Parquet uses HTTP range requests. | { sales: { url: '/data/sales.parquet' } } |
| Fetch callback | You call your own API, return rows | { users: { fetch: () => api.getUsers() } } |
| File | Browser 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.
| Return | Type | Description |
|---|---|---|
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(): DuckThemeReturns 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
| Prop | Type | Default | Description |
|---|---|---|---|
sql | string | required | SQL query to execute |
type | 'line' | 'bar' | 'area' | 'scatter' | 'line' | Chart type |
height | number | 300 | Chart height in pixels |
width | number | auto (fills container) | Chart width in pixels |
title | string | -- | Chart title |
colors | string[] | theme palette | Series colors |
legend | boolean | true | Show legend |
axes | { x?: AxisOptions; y?: AxisOptions } | -- | Axis labels and formatting |
tooltip | boolean | TooltipOptions | true | Tooltip config |
className | string | -- | CSS class |
tableName | string | -- | 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
| Prop | Type | Default | Description |
|---|---|---|---|
sql | string | required | SQL query |
pageSize | number | 25 | Rows per page |
sortable | boolean | true | Enable column sorting |
resizable | boolean | true | Enable column resizing |
striped | boolean | true | Alternate row colors |
maxHeight | number | string | -- | Max scroll container height |
className | string | -- | CSS class |
tableName | string | -- | 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
| Prop | Type | Default | Description |
|---|---|---|---|
sql | string | required | Query returning a single value (first column, first row) |
label | string | required | KPI label |
format | 'currency' | 'percent' | 'number' | 'compact' | (v: number) => string | -- | Value formatter |
currency | string | 'USD' | Currency code (when format is 'currency') |
compareSql | string | -- | Previous period value for % change |
compareLabel | string | -- | Label for comparison (e.g., "vs 2024") |
sparklineSql | string | -- | Time series query for inline trend line |
className | string | -- | CSS class |
tableName | string | -- | 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
| Prop | Type | Default | Description |
|---|---|---|---|
data | QueryResult | null | required | Data to export |
format | 'csv' | 'json' | 'csv' | Export format |
fileName | string | 'export' | Download file name (without extension) |
label | string | 'Export' | Button label |
className | string | -- | 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
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | required | Dashboard.Panel children |
columns | 1 | 2 | 3 | 4 | 2 | Grid columns at full width |
gap | number | 16 | Gap between panels (px) |
padding | number | 24 | Container padding (px) |
className | string | -- | CSS class |
Dashboard.Panel
Grid item wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | required | Panel content |
span | number | 1 | Column span |
rowSpan | number | 1 | Row span |
className | string | -- | 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
| Prop | Type | Default | Description |
|---|---|---|---|
filters | FilterConfig[] | -- | Manual filter configuration |
auto | string | -- | Auto-detect filters from table schema |
source | string | -- | Table to read distinct values from |
className | string | -- | 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.
| Prop | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
options | string[] | -- | Explicit options |
source | string | -- | Table to query DISTINCT values from |
label | string | -- | Display label |
placeholder | string | 'All' | Placeholder text |
MultiSelectFilter
Toggle buttons for multi-select.
| Prop | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
options | string[] | required | Available options |
label | string | -- | Display label |
RangeFilter
Dual-thumb numeric range slider.
| Prop | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
min | number | required | Range minimum |
max | number | required | Range maximum |
step | number | 1 | Step increment |
label | string | -- | Display label |
DateRangeFilter
Calendar-based date range picker.
| Prop | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
label | string | -- | Display label |
Filter SQL Generation
| FilterValue | Generated 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/elementsAll elements are registered automatically on import. Attributes use kebab-case.
<duck-provider>
Root element. Initializes DuckDB-WASM and provides context to child elements.
| Attribute | Type | Default | Description |
|---|---|---|---|
theme | 'light' | 'dark' | 'light' | Built-in theme |
src | string | -- | URL to a data file (CSV, JSON, or Parquet) |
table | string | -- | Table name for the src data |
format | 'csv' | 'json' | 'parquet' | auto-detect | File 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.
| Attribute | Type | Default | Description |
|---|---|---|---|
sql | string | required | SQL query |
type | 'line' | 'bar' | 'area' | 'scatter' | 'line' | Chart type |
height | string (px) | '300' | Chart height |
width | string (px) | auto | Chart width |
title | string | -- | 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.
| Attribute | Type | Default | Description |
|---|---|---|---|
sql | string | required | SQL query |
page-size | string (number) | '25' | Rows per page |
sortable | boolean attr | -- | Enable column sorting (present = true) |
striped | boolean attr | -- | Alternate row colors |
max-height | string | -- | 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.
| Attribute | Type | Default | Description |
|---|---|---|---|
sql | string | required | Query returning a single value |
label | string | required | KPI label |
format | 'currency' | 'percent' | 'number' | 'compact' | -- | Value formatter |
currency | string | 'USD' | Currency code |
compare-sql | string | -- | Previous period value for % change |
sparkline-sql | string | -- | 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>
| Attribute | Type | Default | Description |
|---|---|---|---|
columns | string (number) | '2' | Grid columns |
gap | string (px) | '16' | Gap between panels |
padding | string (px) | '24' | Container padding |
<duck-panel>
| Attribute | Type | Default | Description |
|---|---|---|---|
span | string (number) | '1' | Column span |
row-span | string (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.
| Attribute | Type | Default | Description |
|---|---|---|---|
auto | boolean attr | -- | Auto-detect filters from table schema (present = true) |
source | string | -- | Table name for distinct values |
Individual Filter Elements
<duck-select-filter>
| Attribute | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
source | string | -- | Table to query DISTINCT values from |
label | string | -- | Display label |
<duck-range-filter>
| Attribute | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
min | string (number) | required | Range minimum |
max | string (number) | required | Range maximum |
step | string (number) | '1' | Step increment |
label | string | -- | Display label |
<duck-date-filter>
| Attribute | Type | Default | Description |
|---|---|---|---|
column | string | required | Column to filter |
label | string | -- | Display label |
<duck-export>
Export button for downloading query results.
| Attribute | Type | Default | Description |
|---|---|---|---|
sql | string | required | SQL query to export |
format | 'csv' | 'json' | 'csv' | Export format |
file-name | string | 'export' | Download file name (without extension) |
label | string | '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>:
| Event | detail | Description |
|---|---|---|
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:
| Property | Default (light) | Description |
|---|---|---|
--duck-bg | #ffffff | Background color |
--duck-text | #374151 | Text color |
--duck-primary | #2563eb | Primary / accent color |
--duck-surface | #f9fafb | Surface / card background |
--duck-border | #e5e7eb | Border color |
--duck-grid | #e5e7eb | Chart grid lines |
--duck-hover | #f3f4f6 | Hover state background |
--duck-muted | #9ca3af | Muted text color |
--duck-error | #ef4444 | Error color |
--duck-success | #22c55e | Success 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:
- Registers all Custom Elements (
<duck-provider>,<duck-chart>, etc.) -- use them in HTML immediately. - Exposes
window.DuckUI-- the imperativeDuckUIclass 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 }
| nullChartTheme
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'| Property | lightTheme | darkTheme |
|---|---|---|
| background | #ffffff | #111827 |
| textColor | #374151 | #e5e7eb |
| primaryColor | #2563eb | #60a5fa |
| surfaceColor | #f9fafb | #1f2937 |
| borderColor | #e5e7eb | #374151 |