06 · Runtime inputs
Scenario
The template is generic, but each run targets a specific month or region. You don't want the operator to edit the template — they pass the value in at convert time.
Declare in __inputs__
| name | type | required | default | label | options |
|---|---|---|---|---|---|
month | text | true | Target month (YYYY-MM) | ||
region | select | false | All | Region filter | All|Seoul|Busan|Daegu |
Type values: text, number, date, select.
Use in template cells, filenames, and group keys
Cell: {{ "Report for " & __inputs__[month] }}
Filename: output_file_pattern = {{ __inputs__[month] }}-renewals.xlsx
Filter: {{ @filter [Region] = __inputs__[region] OR __inputs__[region] = "All" }}
Wait — that last one doesn't work as written; XTL has no OR keyword.
The clean pattern is two template sheets, picked by an upstream
condition. For now, the simpler use of __inputs__ is to inject a
literal value into a cell, a filename, or a fixed comparison:
{{ @filter [Region] = __inputs__[region] }}
…and have the host only call convert() after the operator picks a
specific region.
Pass values from the host
import { convert } from '@xl3-lang/xl3';
const outputs = await convert(templateBuffer, dataBuffer, {
inputs: { month: '2026-05', region: 'Seoul' },
});
If inputs.month is missing and month is marked required, xl3
raises xl3/inputs/missing-required at convert time. If region
isn't supplied, it falls back to the default (All).
Source metadata (title, period, values outside the table)
Source exports often carry positional metadata outside the data
table — a report title in A1, a period or 거래처명 in a banner cell,
an author/date in a corner. xl3 reads the source as a table (headers
- rows); it deliberately does not read arbitrary cells from the source workbook by address.
For host-driven flows (your engine calls convert() / convertJson()),
lift such values in the host and pass them as inputs:
// The host already has the title (from the workbook, a DB, an API, …).
const outputs = await convert(templateBuffer, dataBuffer, {
inputs: { ReportTitle: '2026 상반기 정산', Period: '2026-06' },
});
Title: {{ __inputs__[ReportTitle] }} Period: {{ __inputs__[Period] }}
This keeps the source a clean, language-neutral table — so the same
template works with a .xlsx source or a JSON source
(convertJson, the xl3-source-json format) — and keeps cell-address
reading out of the template language. Reading fixed source cells by
address (a SOURCECELL function) was proposed and declined for this
reason (ADR-0071); __inputs__ is the supported path.
Inspect declared inputs without running
import { readTemplateInputs } from '@xl3-lang/xl3';
const inputs = await readTemplateInputs(templateBuffer);
// → [{ name: 'month', type: 'text', required: true, ... }, ...]
Use this in a host UI to render a form before the operator has uploaded the data file.
Computed defaults and labels (ADR-0050)
The default, label, description, and options columns are XTL
templates evaluated at input-read time. You can compose values from
__config__ or call pure scalar functions:
| name | type | default | label |
|---|---|---|---|
title_prefix | text | {{ __config__[region] }} 거래명세서 | Title prefix |
report_date | text | {{ TEXT(TODAY(), "YYYY-MM-DD") }} | Report date |
report_label | text | {{ UPPER(__config__[region]) }}-{{ __config__[period] }} | Report label |
The host UI calling readTemplateInputs() sees the post-evaluation
strings (e.g., "KR 거래명세서", the current UTC date). The user no
longer sees the raw {{ ... }} placeholder.
Available bindings at input-read time:
__config__[key]— values declared earlier in the__config__sheet.- Pure scalar functions:
TODAY,DATE,IF,IFEMPTY,IFS,IFERROR,UPPER,LOWER,TRIM,TEXT,YEAR,MONTH,DAY,EOMONTH,EDATE,DATEDIF,ROUND,ABS.
Not available — these throw at input-read time:
[Column]/Source[Column]— no source row context yet. Error code:xl3/inputs/forward-reference.__inputs__[name]— input rows are independent declarations, not a dependency graph. Same error code.ROW(),SUM,COUNT,AVERAGE,MIN,MAX,XLOOKUP— these read render-state or source data that does not exist yet. Error code:xl3/inputs/runtime-only-fn.
Migration note. Before 0.6,
{{ ... }}in__inputs__cells was treated as literal text. If an existing template had a closed{{ ... }}block intended as literal characters, that string now evaluates as an expression. Most authors will not be affected — the prior behavior was surprising in practice.
Notes
selectoptions are pipe-separated in the__inputs__row (e.g.Seoul|Busan|Daegu). A supplied value not in the options raisesxl3/inputs/select-option. The pipe split runs after the cell template evaluates, sooptions: {{ __config__[regions] }}works when__config__[regions]is the literal stringSeoul|Busan|Daegu.- Date inputs are parsed as
YYYY-MM-DDorYYYY-MM-DDTHH:mm:ss. - Number inputs accept JS number literals; trailing whitespace is allowed.
- Spec reference:
spec/evaluation.md"Inputs"; ADR-0010, ADR-0011, ADR-0050.