1. Ad hoc dialogs with open_dialog
Ad hoc dialogs let an ACF function or a FileMaker calculation collect parameters without building a dedicated FileMaker layout. The dialog is described by JSON, opened as a modal native window, and returns the selected button and field values as JSON.
- Ad hoc dialogs with open_dialog
- Use the Dialog Configurator first
- Opening a dialog in ACF
- Opening a dialog from FileMaker
- Default values
- Applying values to a dialog definition
- Validation loop example
- Dialog actions
- Action parameters
- Action return modes
- Field buttons
- Change events
- Dynamic option lists
- Horizontal radio grids
- Read-only fields and validation
- Prefilling from SQL JSON INTO
- Hidden fields
- Variations
- Common field types
- Practical pattern
The most important functions are:
JSON result = open_dialog(JSON dialogDefinition);
JSON newDefinition = dialog_apply_values(JSON dialogDefinition, JSON values);
From FileMaker calculations, the same features are available as external plugin functions using serialized JSON text:
ACF_OpenDialog(dialogJSON)
ACF_DialogApplyValues(dialogJSON ; valuesJSON)
1.1. Use the Dialog Configurator first ↑
This page describes the current dialog functionality in ACF Plugin 1.7.9.9, available for both macOS and Windows from the download area.
The recommended way to build dialogs is the browser-based Dialog Configurator 1.8.0:

https://horneks.no/manuals/ACF/tools/dialog-configurator-1.8.0.html
The configurator is a visual editor for dialog JSON:
- Add rows, columns, fields, and buttons from the toolbar above the preview.
- Select a row, column, or field in the preview to edit its properties.
- Drag fields between rows and columns.
- Drag rows or columns to change their order.
- Use dashed row and column guides to see the generated dialog structure.
- Configure action callbacks, change events, field buttons, hidden values, variations, colors, text styling, and default values.
- See the dialog preview, JSON, ACF source, and FileMaker calculation output side by side.
The generated FileMaker calculation is especially useful when you want to use ACF_OpenDialog directly from a FileMaker script without writing ACF code. It builds the dialog definition with FileMaker's native JSONSetElement function and wraps it in ACF_OpenDialog(...), so the result can be pasted into a single Set Variable calculation.
The ACF source output generates a ready-to-use JSON definition = ...; JSON result = open_dialog(definition); pattern using JSON() and JSONarray().
This is usually much faster and less error-prone than writing the full JSON object manually. The JSON specification is still useful when you want to build or alter dialog definitions dynamically.

1.1.1. Try it out ↑
You can test a generated dialog directly from FileMaker without writing an ACF function.
- Download ACF Plugin 1.7.9.9 for your platform if you have not already installed it. If you have an older version, update to the latest version.
- Install the plugin.
- Restart FileMaker after installing or updating the plugin.
- Open the Dialog Configurator 1.8.0: https://horneks.no/manuals/ACF/tools/dialog-configurator-1.8.0.html
- Add a few fields of different types. Try text fields, date ranges, select fields, radio buttons, columns, or hidden values.
- Press Download JSON when you are finished. This gives you a file you can load back into the configurator later if you want to make changes.
- Scroll down to the output area at the bottom of the configurator.
- In the right output pane, press FileMaker.
- Copy the generated FileMaker calculation.
- Open FileMaker.
- Choose Tools > Data Viewer.
- Go to the Watch tab and press the small + button in the bottom right.
- Make sure automatic evaluation is unchecked.
- Paste the generated FileMaker calculation.
- Press Evaluate.
The generated calculation calls ACF_OpenDialog(...), so your new dialog should open immediately. When you press OK, the returned JSON result appears in the Data Viewer result pane.
1.2. Opening a dialog in ACF ↑
The open_dialog function accepts one JSON parameter and returns a JSON result. It blocks the ACF function until the user clicks a button or closes the dialog.
function AskForCustomer ()
JSON definition = JSON(
"title", "Customer search",
"subtitle", "Enter search criteria.",
"size", JSONarray(560, 360),
"labelPosition", "left",
"fields", JSONarray(
JSON("name", "Customer", "label", "Customer", "type", "text", "width", "full"),
JSON("name", "Status", "label", "Status", "type", "select",
"options", JSONarray("Open", "Closed", "All")),
JSON("name", "FromDate", "label", "From date", "type", "date")
),
"values", JSONarray("", "Open", ""),
"buttons", JSONarray(
JSON("id", "ok", "label", "Search", "default", true),
JSON("id", "cancel", "label", "Cancel", "cancel", true)
)
);
JSON result = open_dialog(definition);
return result;
end
This gives this dialog:

A typical result:
{
"button": "ok",
"buttonLabel": "Search",
"values": {
"Customer": "Horneks",
"Status": "Open",
"FromDate": "2026-06-20"
}
}
1.3. Opening a dialog from FileMaker ↑
Use ACF_OpenDialog(dialogJSON) when you want to open a dialog directly from FileMaker scripts or calculations.
The Dialog Configurator can generate a FileMaker calculation that builds the JSON definition and calls ACF_OpenDialog in one expression. This is the recommended copy-and-paste workflow for FileMaker-only use.
For FileMaker calculation, press the "FileMaker" button over the tab:

Paste this into the calculation and you are all set.
Set Variable [ $result ; Value: ACF_OpenDialog ( Let ( [
~json = JSONSetElement ( "{}" ;
[ "title" ; "Customer search" ; JSONString ] ;
[ "subtitle" ; "Enter search criteria." ; JSONString ] ;
[ "size[0]" ; 560 ; JSONNumber ] ;
[ "size[1]" ; 360 ; JSONNumber ] ;
[ "labelPosition" ; "left" ; JSONString ] ;
[ "rows[0].fields[0].name" ; "Customer" ; JSONString ] ;
[ "rows[0].fields[0].label" ; "Customer" ; JSONString ] ;
[ "rows[0].fields[0].type" ; "text" ; JSONString ] ;
[ "buttons[0].id" ; "ok" ; JSONString ] ;
[ "buttons[0].label" ; "Search" ; JSONString ] ;
[ "buttons[0].default" ; True ; JSONBoolean ]
)
] ;
~json
) ) ]
Set Variable [ $button ; Value: JSONGetElement ( $result ; "button" ) ]
Set Variable [ $customer ; Value: JSONGetElement ( $result ; "values.Customer" ) ]
ACF_OpenDialog returns serialized JSON text. In ACF code, open_dialog returns a native ACF JSON value.
This avoids using FileMaker layouts or global fields just to collect temporary script parameters. The dialog values exist only in the returned JSON result.
1.4. Default values ↑
Default field values are stored in values arrays beside the matching fields arrays. The first value belongs to the first field, the second value belongs to the second field, and so on.
{
"fields": [
{ "name": "Customer", "label": "Customer", "type": "text" },
{ "name": "Status", "label": "Status", "type": "select",
"options": ["Open", "Closed", "All"] }
],
"values": ["Horneks", "Open"]
}
For rows with columns, each column has its own fields and values arrays:
{
"columns": [
{
"fields": [
{ "name": "FromDate", "label": "From", "type": "date" }
],
"values": ["2026-06-29"]
}
]
}
Range fields use a two-element value array:
{
"fields": [
{ "name": "Period", "label": "Period", "type": "dateRange", "separator": "-" }
],
"values": [["2026-06-01", "2026-06-29"]]
}
The configurator writes these value arrays automatically. The JSON, ACF source, and FileMaker calculation outputs all use the same dialog definition object.
1.5. Applying values to a dialog definition ↑
dialog_apply_values(definition, values) takes a dialog definition and a flat JSON object with field-name/value pairs. It returns a new dialog definition with the values placed in the correct rows, columns, variants, and field definitions.
This means the code that pre-fills a dialog does not need to know where each field is located in the layout.
JSON values = JSON(
"Customer", "Horneks",
"Status", "Open",
"FromDate", "2026-06-20"
);
JSON filledDefinition = dialog_apply_values(definition, values);
JSON result = open_dialog(filledDefinition);
The values parameter can also be a dialog result object. If it contains a top-level values object, that object is used automatically:
JSON result = open_dialog(definition);
JSON retryDefinition = dialog_apply_values(definition, result);
From FileMaker:
Set Variable [ $filledDefinition ; Value: ACF_DialogApplyValues ( $definition ; $valuesJSON ) ]
Set Variable [ $result ; Value: ACF_OpenDialog ( $filledDefinition ) ]
1.6. Validation loop example ↑
Named staticText fields can be updated by dialog_apply_values. This is useful for validation messages.
function PasswordDialog ()
JSON definition = JSON(
"title", "Login",
"size", JSONarray(520, 300),
"labelPosition", "left",
"fields", JSONarray(
JSON("name", "err", "type", "staticText", "text", "",
"decoration", JSON("size", 14, "color", "#ff2600",
"align", "center", "weight", "bold")),
JSON("name", "UserName", "label", "User name", "type", "text"),
JSON("name", "Password", "label", "Password", "type", "password")
),
"buttons", JSONarray(
JSON("id", "ok", "label", "OK", "default", true),
JSON("id", "cancel", "label", "Cancel", "cancel", true)
)
);
JSON result = open_dialog(definition);
if (result["button"] == "ok" && length(string(result["values.Password"])) < 8) then
result["values.err"] = "Password is too short";
JSON retryDefinition = dialog_apply_values(definition, result["values"]);
result = open_dialog(retryDefinition);
end if
return result;
end
Empty staticText fields do not occupy vertical space. If a fixed blank area is desired, use a single space as the initial text.
1.7. Dialog actions ↑
Dialogs can call ACF functions while the dialog is still open. Actions can be attached to footer buttons, field-level buttons, and field change events.
Action callbacks are useful for:
- Picking a file or folder and writing the path into a field.
- Formatting or validating a value when the user leaves a field.
- Looking up database values and applying them to the current dialog.
- Reloading option lists based on another choice in the dialog.
- Enforcing company-specific policy rules before the user closes the dialog.
An action object has this basic shape:
{
"function": "FunctionName",
"params": ["{FieldName}", ":localVariable", "{}"],
"returnAction": "set",
"target": "TargetField"
}
The function is resolved when the dialog opens. If the callback cannot be found or the parameter structure is invalid, the dialog reports the problem immediately instead of waiting until the user clicks a button.
1.8. Action parameters ↑
Action parameters are written as strings in the JSON definition. The dialog resolves them before calling the ACF function.
| Syntax | Meaning |
|---|---|
{FieldName} |
Current value of a field in the dialog. |
{} |
Current dialog result JSON, in the same shape as the final open_dialog return value. This is useful for functions that inspect or modify several values. |
:localName |
Local variable in the calling ACF function. |
$var, $$var, Table::Field |
FileMaker expression-style value, evaluated through the plugin. |
| Any other text | Literal string parameter. |
Parameters are passed in the order they appear in the params array, matching the called ACF function signature.
When writing raw JSON, use the string token "{}". When building the definition with ACF's JSON() and JSONarray() helpers, JSONarray("{}") is also accepted even if the builder stores it as an empty JSON object internally.
1.9. Action return modes ↑
The returnAction value controls what happens with the ACF function result.
| returnAction | Description |
|---|---|
apply |
Treat the function result as JSON values and apply them to the current dialog. This is the default. |
set |
Put the function result into the field named by target. |
setOptions |
Replace the option list for the field named by target. Works with select, list, and radio. |
reload |
Replace the current dialog definition with the JSON definition returned by the callback, keeping the dialog open. |
close |
Let the button continue closing the dialog after the action has run. |
For setOptions, the callback can return:
- a JSON array, for example
["", "Open", "Closed"] - a string containing options separated by CR, LF, or CRLF
- an ACF array value
Blank options are preserved. This is useful when the first option should mean "no selection".
1.10. Field buttons ↑
Use a field with "type":"button" when the button belongs near the data it affects.
{
"name": "ChoosePath",
"type": "button",
"buttonLabel": "Choose...",
"action": {
"function": "SaveFileDialog",
"params": ["Save report", ":folder", ":target"],
"returnAction": "set",
"target": "Path"
}
}
This pattern keeps utility buttons close to their target fields instead of placing everything in the footer.
1.11. Change events ↑
Regular fields can use onChange. Range fields can additionally use onChangeFrom and onChangeTo, so the two sides of a range can trigger different logic.
{
"name": "Name",
"label": "Name",
"type": "text",
"onChange": {
"function": "testFormatName",
"params": ["{Name}"],
"returnAction": "set",
"target": "Name"
}
}
For a date range:
{
"name": "Period",
"label": "Period",
"type": "dateRange",
"separator": "-",
"onChangeFrom": {
"function": "testDateRange30",
"params": ["{Period}"],
"returnAction": "set",
"target": "Period"
}
}
In this example the callback can return a two-value JSON array, such as ["2026-06-01", "2026-07-01"], and the range field is updated in one operation.
1.12. Dynamic option lists ↑
Actions can reload the options for select, list, and radio controls with returnAction:"setOptions".
function myValueListItems ( string valuelist )
string expr = format ('ValueListItems(""; "%s")', valuelist);
string items = eval(expr);
return explode("\r", items);
end
{
"name": "ReloadReports",
"type": "button",
"buttonLabel": "Reload",
"action": {
"function": "myValueListItems",
"params": ["ReportNames"],
"returnAction": "setOptions",
"target": "Report"
}
}
This makes it possible to filter a report list, a destination list, or similar choices without closing and reopening the dialog.
1.13. Horizontal radio grids ↑
Radio fields can be displayed vertically or as a horizontal grid.
{
"name": "Destination",
"label": "Destination",
"type": "radio",
"layout": "horizontal",
"columns": 3,
"options": ["Paper", "Excel", "PDF"]
}
If columns is omitted, the dialog uses an automatic column count. On macOS, reloaded option lists are measured again so longer option labels can reduce the column count instead of being truncated.
1.14. Read-only fields and validation ↑
Fields can be made read-only with readonly:true or readOnly:true. For range fields, readonlyFrom / readOnlyFrom and readonlyTo / readOnlyTo can lock only one side of the range.
Date and numeric-style workflows can use a validation object with min and max values. For ranges, validation can be split into from and to sections.
{
"name": "DuePeriod",
"label": "Due period",
"type": "dateRange",
"readonlyFrom": true,
"validation": {
"to": {
"min": "2026-06-21",
"max": "2026-07-21"
}
}
}
Validation is intentionally local to the dialog control. For database lookups, cross-field rules, or company-specific policy checks, use an action callback and apply the returned values or error message.
1.15. Prefilling from SQL JSON INTO ↑
ExecuteSQL and ExecuteMySQL can write a result set directly into a JSON variable when the SQL ends with INTO :jsonVariable.
This pairs nicely with dialog_apply_values.
function EditPackageSettings ()
JSON definition = JSON(
"title", "Package settings",
"labelPosition", "left",
"fields", JSONarray(
JSON("name", "PackageKey", "label", "Package key", "type", "text"),
JSON("name", "Name", "label", "Name", "type", "text", "width", "full")
),
"buttons", JSONarray(
JSON("id", "ok", "label", "OK", "default", true),
JSON("id", "cancel", "label", "Cancel", "cancel", true)
)
);
JSON data;
string sql = "SELECT PrimaryKey AS PackageKey, Package_Name AS Name
FROM ACF_Packages
INTO :data";
string res = ExecuteSQL(sql);
if (data["success"] && data["rows_found"] > 0) then
JSON firstRow = data["result[1]"];
definition = dialog_apply_values(definition, firstRow);
end if
return open_dialog(definition);
end
1.16. Hidden fields ↑
Dialog definitions can include hidden values that are returned with the visible field values. Hidden fields are useful for primary keys, mode flags, record state, or other data that should travel with the dialog result without being displayed.
{
"title": "Edit customer",
"hidden": {
"CustomerID": "A123",
"mode": "edit"
},
"fields": [
{ "name": "CustomerName", "label": "Customer", "type": "text" }
]
}
Result:
{
"button": "ok",
"values": {
"CustomerID": "A123",
"mode": "edit",
"CustomerName": "Horneks"
}
}
1.17. Variations ↑
A dialog can contain alternative field sets controlled by a selector. This is useful when one dialog supports several report types, import modes, or settings pages.
Important root options:
| Key | Description |
|---|---|
selector |
Defines the controlling selector and its options. |
variants |
Field layouts keyed by selector option values. |
variationStyle |
"select" uses a popup selector. "tabs" uses tab-style variant selection. |
variationResult |
"current" returns only the selected variant's fields. "all" returns values from all variants. |
Example:
{
"title": "Report settings",
"variationStyle": "tabs",
"variationResult": "current",
"selector": {
"name": "ReportSource",
"label": "Report source",
"options": ["Offers", "Orders", "Invoices"],
"value": "Orders"
},
"variants": {
"Orders": {
"fields": [
{ "name": "OrderNo", "label": "Order no.", "type": "text" }
]
},
"Invoices": {
"fields": [
{ "name": "InvoiceNo", "label": "Invoice no.", "type": "text" }
]
}
}
}
With variationResult set to "all", fields with the same name in multiple variants are returned as arrays, following the same duplicate-name rule used elsewhere in dialog results.
1.18. Common field types ↑
| Type | Description |
|---|---|
text |
Single-line text field. |
password |
Single-line masked text field. The result contains the clear typed value. |
textarea |
Multi-line text area. |
checkbox |
Boolean checkbox. |
select |
Popup selector. |
radio |
Radio-button group. |
list |
Selectable list area. |
date |
Date field with popup calendar. |
time |
Time field. |
dateRange |
Two date fields with a separator. |
textRange |
Two text fields with a separator. |
staticText |
Text block, often used for descriptions or validation messages. |
button |
Field-level button that can run an action callback. |
Most dialogs should be built with the configurator, but these field names are useful when reading or modifying generated JSON.
1.19. Practical pattern ↑
For many workflows, the cleanest pattern is:
- Build the dialog definition in the configurator.
- Store the JSON definition in FileMaker or in an ACF function.
- Fetch current values as a flat JSON object.
- Use
dialog_apply_valuesto prefill the dialog. - Use
open_dialogorACF_OpenDialogto collect edits. - Validate the result and reopen with a named
staticTextmessage if needed.
This keeps FileMaker layouts free of global utility fields and keeps dialog logic close to the code that uses the result.
