Convert an Airtable table or view into an HTML table with configurable columns, field resolution, transforms, rendering, and output formatting.
The package is written as native, erasable TypeScript. Development and tests run
directly from .ts source through Node's built-in type stripping. Compilation is
optional and only performed by npm run emit.
When omitted, airtable2html uses:
- the first five fields in the selected table;
- the first 100 records returned by the table or view;
- Airtable string-form cell values;
- escaped, minified HTML output;
- field names as column headers.
A view affects record filtering, sorting, and ordering. It does not determine the output fields.
const { airtable2html, airtableScripting } = await import(
'https://esm.sh/gh/dddominikk/airtable2html@<commit>'
);
const config = input.config({
title: 'Export Airtable to HTML',
items: [
input.config.table('table', { label: 'Table' }),
input.config.view('view', {
label: 'View',
parentTable: 'table',
}),
],
});
const html = await airtable2html({
adapter: airtableScripting({ base }),
source: {
table: config.table,
view: config.view,
},
});
output.markdown(html);Pin production imports to a commit hash or release tag rather than the default branch.
Columns are emitted in configuration order. Field references are resolved case-insensitively by ID, name, then aliases. Supplying both the immutable field ID and current name gives rename resistance plus readable configuration.
const html = await airtable2html({
adapter: airtableScripting({ base }),
source: {
table: 'tbl6Xno8SQ5hv39nV',
view: 'viwXXXXXXXXXXXXXX',
},
columns: [
{
field: {
id: 'fldK8uiOyi8NNf38N',
name: 'Game',
aliases: ['Title'],
},
header: 'Game',
},
{
field: 'fldshK53iuO9EIGld',
header: 'Platform(s)',
transform: 'xgp.platforms',
},
],
transforms: {
'xgp.platforms': (_value, context) =>
context.stringValue.split(/,\\s*/u).sort().join(', '),
},
});const markdown = await airtable2html({
adapter: airtableScripting({ base }),
source: { table: 'Games', view: 'Published' },
records: { limit: 50 },
output: { format: 'markdown' },
html: {
pretty: true,
tableAttributes: {
border: 1,
cellpadding: 1,
cellspacing: 1,
},
headerCellAttributes: { style: 'text-align:center' },
cellAttributes: { style: 'text-align:center' },
},
});Supported output formats are html and fenced markdown.
The convenience function is composed from two independent stages:
const model = await createAirtableTableModel(config);
const html = renderHtml(model, { pretty: true });
const markdown = renderMarkdown(model);The model preserves resolved field metadata, raw and transformed cell values, record IDs, record counts, and truncation state. Custom renderers can consume the same model without querying Airtable again.
A transform can be an inline function, a named function in transforms, or a
built-in transform reference with options.
Built-ins:
identityfallbackjoinregexReplacetrimnumber.score(rating.openCriticis an alias)
columns: [
{
field: 'OpenCriticAvg',
transform: {
name: 'rating.openCritic',
options: {
min: 0,
max: 100,
default: 'N/A',
},
},
},
{
field: 'Duration',
transform: {
name: 'regexReplace',
options: {
pattern: '^(\\d+)\\s*-\\s*(\\d+)$',
replacement: '$1–$2 hours',
},
},
},
]number.score parses finite numeric values from numbers or strings. Empty,
invalid, out-of-range, and (by default) negative values return N/A or the
configured default. allowNegative defaults to false. precision defaults
to the resolved Airtable field's precision when available and can be overridden
per transform.
Transform context includes the raw value, Airtable string value, resolved field, record, record ID, row and column indexes, and transform options.
Requires Node.js 22.18 or newer.
npm install
npm run validateNo build step is used for normal development:
node examples/basic.airtable.ts
node --test test/*.test.tsType-check without emitting:
npm run checkExplicitly emit JavaScript and declarations:
npm run emitGenerated files are written to dist/ and are not used by the GitHub/esm.sh
source entry point.