Product updates

What’s new in v2.x

Major release
Current release2.6.0.0Released 11 October 2026

Modern DFFS 2.0 is a major release: three license tiers, an AI Assistant, tenant-wide governance, and a large set of new form elements, field enhancements and developer tools. This page summarizes what changed for you as a user — follow the guide links for step-by-step setup and worked examples.

Looking for the older history? See the 1.x changelog.

Known issues

  • A new extension version may not load straight away. When a command-set extension is updated, SharePoint can keep serving the previous version from the browser cache. Clear the cache to pick the new one up immediately, or simply wait — the cache clears itself after roughly 15 minutes.

Release history

Need an older build? Browse all published versions, or the v1.x archive. To hear about new releases, subscribe to the Modern DFFS releases RSS feed in any feed reader.

2.611 October 2026

Form tests linked to the rules they check, a repair for “Form load” rules that stopped working after tests were run, rules on Number, Currency and Attachments fields that finally match as configured, and getFieldValue returning text for autocomplete fields.

Behaviour changes — read before upgrading

Five changes alter what an existing, untouched form or script does. All five are corrections.

  • “Form load” rules that had stopped working start working again. Running form tests in the configurator and then saving could leave a marker on every rule that made the form skip rules triggered on Form load (see Bug fixes). Affected forms are repaired automatically, with no re-save needed. Those rules will now do what they were configured to do — a field they make required becomes required again. If you have run form tests and then saved a configuration, check that form after upgrading.
  • Rules on Number and Currency fields match amounts of 1,000 or more. Conditions compared the amount as the form displays it — 10 000 or 10,000 — so is equal to failed from 1,000 up, and greater than / less than never matched at all. Rules that never fired for large amounts will now fire as configured — on an approval form, that can change who is asked to approve.
  • Rules on the Attachments field run when a file is added or removed, not only when the form loads. A rule such as Attachments is not empty → show a field now follows the files as the user adds and removes them.
  • getFieldValue on a text field rendered as an autocomplete search box returns the selected text Professional & Enterprise. Once a value had been picked it returned the search box’s internal option objects instead. Custom JS that read .key, .name or .itemData from it will no longer find them — that was undocumented and only worked after a selection.
  • [[fieldValue:…]] on a multi-value Multiple lines of text field rendered as an autocomplete puts each value on its own line. The values previously ran together with no separator. Single-value fields are unchanged.

New features

Form tests and rules, linked Professional & Enterprise

Form tests now know which rules they check. A rule with tests shows an N tests pill in the Rules tab, with a menu listing the tests that check the rule itself and those that check what it does — click one to jump to it — and Run these tests, which runs just those and opens the result. Deleting a rule that tests depend on now asks first and lists them.

In the Tests tab:

  • Notes — record why a test exists. The first line shows under the test name.
  • Saved results — each test keeps its last result between sessions, marked Rule changed when a rule it is linked to has been edited since it last ran.
  • Duplicate, and Copy to paste into another form — for example from the New form’s tests to the Edit form’s. A copied test can be discarded without pasting it.
  • Rules without tests — a list of the enabled rules no test covers yet.
  • Create a rule from this test — drafts the rule a test describes: its values become the condition, its checks become the actions, and the rule undoes itself when the condition stops matching. You review it before saving.
  • The test editor now opens in place of the test being edited, rather than below the whole list.

Form tests guide →

Changes

  • Attachments rule conditions count the files — conditions on the Attachments field now offer is empty, is not empty, is changed, is changed from initial value, and comparisons on the number of files: number of attachments is equal to / is not equal to / is greater than / is greater than or equal to / is less than / is less than or equal to. The count includes files added in the form that are not saved yet, and is changed notices one file being swapped for another. Most of the old operators could never match correctly — is equal to Yes never matched, for example. Rules saved with the old Yes/No value keep working, and are converted to is empty / is not empty the next time they are opened.
  • The repeating section no longer offers document libraries as the child list Professional & Enterprise — rows in a repeating section are list items, and adding one to a library always failed when the form was saved. Use a vLookup to show and upload documents related to the item.
  • The configuration cannot be saved while a form test is running or being recorded Professional & Enterprise — Save shows Finish the test first and asks you to stop the recording or let the test finish. Run these tests before saving the configuration is unaffected.

Bug fixes

  • Rule conditions on Number and Currency fields compared formatted text — see Behaviour changes. Conditions now compare numbers, and can be written with or without thousand separators. Form tests that check a number or currency value are fixed the same way.
  • Running form tests could make the configuration look edited Professional & Enterprise — so closing the configurator asked about unsaved changes that were not there.
  • After a form test run on the live form, fields could stay as the test left them Professional & Enterprise — for example, a field a rule shows only for large amounts stayed visible after the test that set a large amount. The rules now run once more on the restored values when the run ends, so the form is back to how the user sees it. Emails, webhooks and flows that ran when the form opened are not sent again. Running tests on the real form →
  • A test’s result listed actions from the form’s own load rules as if the test had caused them Professional & Enterprise — such as a message box a rule shows when the form opens, which appeared in every test. They are now listed separately, under Intercepted while the form loaded.
  • Rules triggered on “Form load” could stop working after form tests were run Professional & Enterprise — a test run left a “this rule has already run” marker on the rules, which was saved with the configuration and made the form skip them on load. The marker is no longer saved, and it is ignored in configurations that already contain it, so affected forms work again without any change.
  • Rules on the Attachments field never re-ran when a file was added or removed — see Behaviour changes. Custom JS dffs_fieldChanged now fires for Attachments too, with the new and previous file lists.
  • getFieldValue returned option objects for an autocomplete text field Professional & Enterprise — see Behaviour changes. Passing that value on to setFieldValue could make SharePoint reject the whole save with “An unexpected startArray node was found when reading from the JSON reader”. It now returns the text that is saved to the item, for both SharePoint list and REST endpoint data sources. getFieldValue reference →

2.56 October 2026

Rules that check Entra ID (Azure AD) group membership — including Entra ID groups nested inside a SharePoint group — and a fix for dffs_vLookup_callback running before the vLookup had rendered.

Behaviour changes — read before upgrading

Two changes alter what an existing, untouched test or script does. Both are corrections.

  • A form test’s pinned SharePoint groups are now actually used Professional & Enterprise. A test definition can list the SharePoint groups the simulated user belongs to (context.userGroups — the Tests tab has no editor for it; only the date can be pinned there). That list had no effect on the group conditions it was meant to exercise. It does now. A test that passed only because its group list was ignored will now fail.
  • dffs_vLookup_callback runs once the vLookup has rendered Professional & Enterprise. See Bug fixes. If your vLookup has an asynchronous prepare function, the callback now runs after that function has finished rather than before it started.

New features

Entra ID groups in rule conditions Professional & Enterprise

Rules can now check whether the current user is a member of an Entra ID (Azure AD) group — a security group or a Microsoft 365 group — with a new Entra ID group condition (User is a member of / User is not a member of Entra ID group). Membership counts groups reached through other groups, too.

A SharePoint group condition has a new option, Also match Entra ID groups that are members of this SharePoint group. This closes a long-standing gap: a user whose access came only through an Entra ID group nested inside a SharePoint group was treated as not being in the group at all, so a rule written as is not in group showed them exactly what it was meant to hide. The option is off by default, so upgrading does not change who an existing rule matches. The nested groups are looked up when you save the configuration, with your permissions, and the condition shows when that was done, with a Refresh button.

No tenant setup is normally needed. The permission this uses — Microsoft Graph User.Read, which only lets a user read their own information — is normally pre-authorized by Microsoft for SharePoint Framework solutions, and Modern DFFS still asks for no API permissions of its own. If the permission has been removed, or a particular user cannot get a token for it (a Conditional Access policy, or an external guest), a rule using these conditions is skipped — no actions run — rather than treated as not a member, so a rule can never reveal something by failing. The configurator tells you while you are building the rule if membership cannot be read in your tenant, and Rule Debug shows a skipped condition as an amber ?. Graph is only called by forms that use these conditions.

You can pick a group by name where your tenant allows listing groups; otherwise paste the group’s object id from the Entra admin center.

Custom JS: dffs_isMemberOfEntraGroup, dffs_getEntraGroupMemberships, dffs_entraGroupsAvailable and dffs_entraGroups give scripts the same membership check. Form tests: a test run in the configurator never calls Microsoft Graph, so a rule that depends on an Entra ID group is listed on the result as a condition that could not be evaluated, instead of reading as a rule that did not fire. A run on the real form makes the real lookup. A test definition can also fix the user’s Entra ID groups (context.entraGroups), the same way as context.userGroups. Custom JS API reference → · How DFFS uses Microsoft Graph →

Bug fixes

  • dffs_vLookup_callback could run before the vLookup had finished rendering Professional & Enterprise — since 2.3, custom code that read the vLookup’s rows or its “no items” message inside the callback did not find them. The callback now runs once the vLookup has rendered.
  • dffs_userGroups was documented as an array Professional & Enterprise — it is a lookup keyed by group title and group id, so dffs_userGroups["Approvers"] === true is the way to test it; .length, .forEach and .map never worked on it. The in-editor help and the Custom JS reference now say so.

2.44 October 2026

Side panels from Custom JS, a notice in the configurator when a new version is out, a CSS class per tab, drag-to-reorder for vLookup columns, a light theme for the code editor, and an import that checks it is importing a real configuration.

Behaviour changes — read before upgrading

Three changes alter what an existing installation, configuration or script does.

  • The configurator now checks spjsworks.com for a newer version. Once per browser session, and only while someone has the configurator open, it reads a small public file holding the latest version number. The request carries no license, user, list or form information, and opening or filling in a form never makes this request. If the site cannot be reached, nothing is shown and nothing breaks. If your security team keeps a list of the connections DFFS makes, this is a new one — it is listed in the Architecture & Security overview, and Enterprise customers can turn it off for the whole tenant (see below).
  • Import configuration refuses a file that is not a usable configuration. It used to check only that the text was valid JSON. A file that imported before may now be refused, with the reasons listed. See Changes.
  • dffs_selectTab called from a vLookup child form now switches the child form’s tabs Professional & Enterprise. It used to act on whichever form had drawn itself last, and could keep pointing at a child form after it closed. Custom JS that relied on that will now act on the form it runs in.

New features

A notice when a new version is released

The configurator now shows a notice when a newer version of Modern DFFS has been published, naming the version you are running and the new one, with a What’s new link straight to that release on this page. Dismiss hides it until the next release comes out.

Enterprise customers can turn the check off for the whole tenant by adding a DisableUpdateCheck item to the central DFFS_Settings list — any value other than 0, false, no or off turns it off. Admin › About › Enterprise status shows whether it is on. Central settings reference →

Side panels from Custom JS — dffs_showPanel Professional & Enterprise

dffs_showPanel opens a dialog pinned to the right, left, top or bottom edge of the screen instead of in the middle — useful for reference information or instructions a user needs to read while still seeing the form. It takes the same options as dffs_showModal, plus position and size (pixels or any CSS length, such as "40%"), and closes with dffs_hidePanel or dffs_hideModal. Unlike a modal, clicking back onto the form closes it, unless you set isBlocking: true.

Panels carry the dffs-panel and dffs-panel-right / -left / -top / -bottom classes for Custom CSS, and their width (or height, for top and bottom) can be restyled through the --dffs-panel-size variable. Custom JS API reference →

A CSS class on an individual tab

Each tab in Edit tab set can now be given its own CSS class in a new Button class field, next to the existing Button style. The class goes on the tab button in the tab bar and on the matching button when Show the tab controls as a separate element is used. It does not follow a tab moved into the ··· overflow menu.

Drag to reorder vLookup columns Professional & Enterprise

The columns under Select fields to display — and the prefill fields under Add new item — can now be reordered by dragging the icon at the left of each row, instead of one step at a time from the row menu. A placeholder opens where the column will land. Move up and Move down are still in the row menu for keyboard use. Reordering also no longer collapses the row you had open and expands an unrelated one. vLookup guide →

Light or dark code editor Professional & Enterprise

The Custom JS and Custom CSS editor can be switched between a dark and a light theme from the sun/moon button in the editor toolbar, or from the right-click menu. The choice is remembered for next time.

Changes

  • Import configuration checks the configuration, not just the JSON — anything that would break the form is listed and the import is refused, so a wrong file can no longer overwrite a working configuration: a missing form layout or rules section, a column without a size, a rule without a condition, elements nested where they cannot go (a column inside a column is the usual one), an element id used twice. Things that are merely suspect — an element type this version does not know, a missing Custom JS or Custom CSS (which would clear the current one), fields that do not exist in this list — are listed with an Import anyway button.
  • Reordering tabs in Edit tab set shows where the tab will land — the same placeholder the vLookup columns use. Dragging a tab no longer collapses the tab you had open, and a drag cancelled with Escape leaves the order alone.
  • The Add dynamic content menu is wider, and hovering an option shows its full label — long field names and token descriptions were cut off with no way to read them.

Bug fixes

  • Append-only history lost its line breaks — a plain text multiline column with Append Changes to Existing Text showed each entry run together on one line. Line breaks are now kept on the display and edit forms, in vLookup columns and in the PDF export.
  • Separate tab controls in a child form switched the parent form’s tabs — when Show the tab controls as a separate element was used on a form that a vLookup also opens as a child form, clicking those buttons in the child form switched tabs on the parent instead. Tab switching — from the separate controls, the multistep buttons, the mobile tab menu, the Select tab rule action and dffs_selectTab — now always targets the form it was triggered from.
  • A child form could report its configuration as missing — a form opened from a vLookup, a Related items link or a lookup column link did not find its configuration when that configuration was stored under the older list-GUID name.
  • Importing a configuration renamed the configuration item — importing, or restoring a restore point, renamed the configuration’s list item to the list GUID. The item now keeps the name it had.
  • The fullscreen code editor’s toolbar was hidden Professional & Enterprise — expanding the Custom JS or Custom CSS editor to fullscreen put its own toolbar behind the configuration panel’s header.
  • Two Custom JS autocomplete snippets left a value empty Professional & Enterprise — dffs_spGet and dffs_showDialog inserted top and width with no value, and put the cursor there instead of on the first argument.

2.324 September 2026

Form tests you can run on the real form, a new {assetUrl} token for scripts and stylesheets hosted outside SharePoint, current-list tokens, stable CSS classes for tabsets, and a large responsiveness fix for forms with many managed metadata columns.

Behaviour changes — read before upgrading

Three changes alter what an existing, untouched form or test does. All are corrections, but each is visible without anyone changing a configuration.

  • A multiline plain text field now opens at the height the column asks for. These fields ignored the column’s Number of lines for editing setting in list settings and always started as a fixed three-line box. They now honour it — six lines unless the column says otherwise — and still grow as you type past it. Forms with plain text multiline fields will be taller than they were; set the column’s number of lines to choose the height.
  • A field hidden by a rule or by Custom CSS now counts as hidden in a test. The field is shown / hidden check asked only whether the field was on the form, so a field hidden with the Hide element action or with Custom CSS — both of which leave it in place and only hide it — was reported as shown. An existing test that relied on that will now correctly fail. A field on a tab the user has not selected still counts as shown, as before.
  • Version history lists changes it could not see before. Columns whose internal name contains an underscore were missing from every version, and a version in which a field was emptied looked like a version in which nothing happened to it. Both are reported now. Expect existing items to show history entries that were not there previously — the changes always happened, the panel could not see them.

New features

Tests — run them on the real form Professional & Enterprise

Tests saved with a form’s configuration can now be run against the live form, not only in the configurator. Add ?dffs_tests=1 to the form’s URL and a Form tests button appears alongside Rule Debug, for anyone who can manage the list. dffs_showFormTests() in the browser console does the same thing without editing the URL.

The form really reacts — values are set, rules run, and this time your Custom JS runs too. A rule condition that calls a custom function calls the real one and uses its answer, unless the test case pins a result for that function, which still wins in both places. The functions that were called are named on the result, so you can see which answers came from your own code.

  • The item is never saved. Save, Ctrl+S, dffs_triggerSave and the autosave timer are all refused for the duration of a run, no draft is written, and the form is returned to its starting values afterwards.
  • Actions that reach outside the form are recorded, not carried out — send email, write to another list, trigger a Flow, call a webhook and show a message box, exactly as in the configurator.
  • Custom JS actions are opt-in per run — a checkbox in the panel, off by default and never remembered, because an action function is meant to do something to a real item.
  • dffs_spAdd, dffs_spUpdate and dffs_spDelete refuse to write while a test runs, and the refusal is listed on the result. A condition function whose write is refused is treated as No and the rest of the rule still evaluates, so one blocked write no longer takes the whole rule down with it. This removes a sharp edge rather than making arbitrary code safe: Custom JS that calls PnP or fetch directly is beyond reach, and the panel says so.

Two differences to know about. A run on the real form sees only the saved configuration, so a rule change has to be saved before it can be tested there. And the run starts from the item that is open, so any field a test does not set itself carries that item’s value — the same test can pass on one item and fail on another. The configurator stays the fast loop for “did I break rule #7?”; the real form answers “does this work for a real user?”. A collapsible “Where do these tests run?” block on the Tests tab explains both.

Tests — check what the user sees, not just that the rule fired Professional & Enterprise

A test can now check whether an HTML section, custom row, row, column or any other element is shown or hidden. Pick it from a list holding the form’s content elements and everything the rules can show or hide, or type an element id — or a CSS class, starting with a dot — for anything else. Recording a test proposes these checks automatically for elements that appeared or disappeared while you filled the form in.

A check like this describes what the user actually sees, so it keeps working when the rule behind it is renamed, split in two or reordered. When one fails it now names the cause rather than saying only that the element is hidden — naming the row or column responsible when the element itself is not. The field is shown / hidden check reports the same way. Form tests guide →

{assetUrl} — externally hosted scripts and stylesheets follow the configuration

Load external JS files and Custom CSS support a new {assetUrl} token alongside {currentSite} and {currentWeb}. Set an asset base URL per environment — a CDN, an Azure blob container, or any folder holding your shared scripts, stylesheets and images — on each stage’s row under Environment settings, and one configuration loads each environment’s own assets with no path edited on promotion. The token works in the external file list and anywhere in Custom CSS, including @import and url(), so webfonts and background images travel with it too.

A site that is in no environment mapping — a sandbox, a customer’s own site, a list that was never added — falls back to the PRD asset URL, so a copied configuration keeps working. If nothing is configured at all the token is deliberately left as it is, so the error message names it instead of reporting a mysterious 404.

Two things worth knowing before pointing this at a storage account. External JS files are fetched by the form rather than added as a script tag, so a script hosted on another domain only loads if that server allows cross-origin requests (CORS) from your SharePoint domain; stylesheets and images loaded from Custom CSS do not need this, and a script blocked this way now says so instead of reporting the same generic load failure a missing file does. And an asset URL containing a SAS token is stored in the form configuration, visible to anyone who can open the configurator — a container with public read access is the safer setup.

Reference panels on the Custom JS and Custom CSS tabs — both tabs now carry the same collapsible reference panel covering the URL tokens, the stable dffs-* CSS classes and how external files are loaded. Collapsed by default, and it remembers whether you left it open. Custom CSS reference →

Current list tokens on the Add dynamic content menu

The Add dynamic content menu has a new Current list section offering the list title, the list ID (GUID) and the list root folder (URL name). The GUID comes out in the form the REST API expects, so it can be pasted straight into a filter or an external file URL.

Related fix: the list and web tokens now describe the list and web the form itself belongs to. In a vLookup child form opened against another list or another web, [[web:absoluteUrl]], [[web:title]] and the list tokens returned values for the page the form was opened from rather than for the child form’s own web. [[site:*]] is unchanged — the page only ever knows one site collection, and {currentWeb} is the answer for a child form in another one. Dynamic content reference →

Tabsets — CSS classes for tab rows, controls and group labels

Tabsets now carry stable class names that Custom CSS can target: dffs-tab-row on the tab row, dffs-tab-external-controls (and -vertical) on the external tab control strip, dffs-tab-mobile-nav on the mobile tab menu, dffs-tab-sticky on a sticky tabset, and dffs-tab-pinned on whichever element is currently pinned to the top of the page. Tab group labels gained an inner element, dffs-tab-label-inner, so padding and margins can be put on the label without being added to the strip’s own layout — which on a pinned vertical strip was enough to produce a scrollbar.

ThemeBuilder gains a Tab row group under Tabs Enterprise / Pro add-on, for the tab row’s background, padding and bottom border — the bottom border previously had no editor at all. Theme Builder guide →

Repeating Section — predefined values and parent links Professional & Enterprise

A predefined field value is now converted to whatever the target column accepts, so writing the parent item’s ID into a text column, a number into a text column, or a date into a date column all work. Previously a mismatch made SharePoint reject the whole row, which looked like the row simply not being saved.

  • Lookup and Person columns can be filled by item ID — use [[fieldValue:ID]] for the parent item, or a token ending in .LookupId for a lookup on the form. The configuration panel now says so where the value is entered.
  • Predefined values are resolved when the form is saved rather than when the row is added, so [[fieldValue:ID]] works on a new form, where the parent item does not exist yet.
  • The parent link field can be a Number column holding the parent item’s ID, alongside a single-value Lookup and a Single line of text. For a text parent link you can now pick ID as the source field on the parent form; on a new form the rows are written with the new item’s ID when you save. The source field list is limited to Text, Choice and ID — the types that can be matched back reliably.
  • A column whose internal name starts with an underscore — _DFFSID, the field the configuration panel recommends as a parent link — now works both as a parent link and as a section column.

Repeating Sections guide →

Changes

  • Large forms with managed metadata fields are usable the moment they appear — a form with many managed metadata columns could be completely unresponsive for up to half a minute after loading, with clicks and keystrokes queued up and played back once it caught up, and moving between fields sluggish afterwards. Each managed metadata field was announcing its value as its term set finished loading, and every one of those announcements redrew the whole form. The form now ignores that echo, and the redraws it genuinely needs are batched into one per frame rather than run one after another. On the form this was reported against — 11 term sets and around 60 lookup, person and calculated columns — the longest blocked moment went from 27 seconds to 0.6, and the longest wait before a click was handled from 26 seconds to 0.24. Nothing needs configuring and nothing about how the fields behave has changed. The ShellException … IFrameRequest console error that showed up alongside this — it comes from Microsoft’s own suite shell — was a symptom of the blocked page and goes away with it.
  • Show element and Hide element no longer log a red error for a target that is not on screen — most of the time this meant nothing was wrong: an element inside a tab that another rule has hidden is not there to be found, and does not need hiding. The message is now plain information and explains the likely reason. It is still shown, so a mistyped id or class is still easy to spot.

Bug fixes

  • “Apply these settings to: All forms for this list” saved the environment settings to one form only — in the Environment setup panel, the panel the new {assetUrl} token is configured in, choosing to apply the DEV/SIT/UAT/PRD settings to all forms for the list stored them on the form being edited and nowhere else, without reporting anything. The other forms are updated now, including forms whose configuration has never been saved, and saving again repairs a form the settings did not reach the first time. Three further corrections in the same panel: Save saves the configuration rather than only staging the change, so the settings can no longer be thrown away by closing the configurator afterwards; switching a form back to Only this form releases the other forms instead of leaving them linked and pushing an older mapping back over it; and the list name field now says which name it wants — the list URL name, not the display name.
  • Sticky tabs stayed pinned when scrolling back up — a sticky tab row or external tab control strip pinned correctly on the way down, but on the way back up it could stay pinned over the top of the form, covering content that had scrolled back into view and ending up above the form’s own command bar once the page reached the top. A form containing a wide element was enough to trigger it. A sticky row now decides when to let go from where the row belongs on the page rather than from how far the page has scrolled, follows the form header as it moves, and tracks its column’s width when the window is resized.
  • Multiline plain text fields jumped while you typed — typing in a plain text field that had grown tall with a long text moved the page on every keystroke, leaving the line being written at the very bottom of the screen. The resize handle in the corner of those fields also works properly now: drag the field smaller and the text you can no longer see is reachable with the scrollbar and the mouse wheel, and the height you chose is kept instead of being reset as soon as you type.
  • Version history skipped fields with an underscore in the internal name, and fields that were emptied — the panel listed no column whose internal name contains an underscore, which affects more than it sounds like: a column created with a space in its name has an underscore in its internal name too. And only setting a value was reported, never clearing one; a field cleared in a version is now listed as (cleared). See the behaviour note above.
  • An append-only field showed an empty box on the display form — a multiline field with Append Changes to Existing Text turned on showed an empty field above the list of entries when the item was opened for viewing. The entries themselves are all that is shown now.
  • A repeating section could add the same rows twice Professional & Enterprise — saving without closing the form and then saving again duplicated the rows added in that session.
  • Tests in the configurator ran against the wrong rendering Professional & Enterprise — a run started from the Tests tab evaluated the builder’s own view of the form, where Show element and Hide element matched nothing at all, so the rules under test did not do the thing being tested. A run now switches to the form preview for its duration and returns you to the tab you started from. Three related fixes: an element hidden by one test case is put back before the next case runs, a recording no longer proposes a check for every content element on the form, and a run waits for show/hide work that is still in flight before checking the result. The Rule Debug pill in the configurator also moved to the opposite corner, where it no longer covers the Tests tab’s Save test button, and the check-type dropdown no longer truncates its own options.

2.221 September 2026

Portable asset paths, Repeating Section calculated columns that save their result, two new Custom JS callbacks, faster managed metadata fields, and a set of cross-site and side-panel fixes.

Behaviour changes — read before upgrading

Two changes alter the value of something Custom JS reads. Both are corrections — the old values were wrong — but existing Custom JS written against them needs checking.

  • dffs_formcontext.serverRelativeUrl now holds the site URL, not the list URL. It returned /sites/Demo/Lists/Case where the name says — and every other SharePoint API using it means — the site: /sites/Demo. The list path is still on the same object as folderPath (the item’s folder, defaulting to the list root), and the list’s URL segment as listUrlName. Code written expecting a site URL now works as intended; code that compensated for the old list URL should use folderPath instead. In a vLookup child form it is now the site that child list is on, rather than the parent form’s.
  • Every element callback now identifies its element the same way. The two Repeating Section callbacks receive repeatingSection_{id} — the id shown in the configuration — in place of the id without that prefix, matching the vLookup callbacks and the DOM id. If you have Custom JS comparing that argument against a value of your own, add the repeatingSection_ prefix to it.

New features

Portable asset paths in Custom JS and Custom CSS

A configuration used by several forms, copied between sites, or promoted through DEV/UAT/PRD no longer needs its asset paths edited by hand at every destination. {currentSite} resolves to the site collection the form is in, and {currentWeb} to the site (web) it is in — for example {currentSite}/SiteAssets/helpers.js in Load external JS files, or @import "{currentSite}/SiteAssets/styles.css"; in Custom CSS.

They work in the external JS file list and anywhere in Custom CSS — including @import and url(), so images stored in SiteAssets travel with the configuration too — as well as in Global Custom CSS and the Default Theme. Coming from classic DFFS, ~sitecollection and ~site work as well. Custom CSS reference →

Repeating Section Professional & Enterprise

  • A calculated column can now also save its result to a real column — pick one under Also save the result to in the calculated column dialog (Text, Multiple lines of text, Number or Currency). The result is written each time the row is added or edited through the form, so the number is available in views, exports and flows rather than only inside the form. Rows that are not edited again keep the value stored with them, so changing a formula later does not restate existing rows.
  • Predefined field values — a list of field/value pairs written to every row added through the section without being shown as a column, the same idea as a vLookup’s prefill values. Tokens are resolved when the row is added, and a predefined value never overwrites a column the user can edit in the section.
  • The configuration now shows the element id, the same as other element types — both the id used in rules and Custom CSS, and the id passed to the Custom JS callbacks.

Custom JS — new callbacks Professional & Enterprise

  • dffs_repeatingSection_callback(elementId, action, data) — fires when a row is added, updated or removed, or the inline editor is cancelled. Rows are staged and only written when the parent form is saved, so this reports the user’s action rather than the write.
  • dffs_vLookup_itemChanged_callback(vLookupId, action, itemId) — fires when a vLookup item is added, updated or removed, or the child form is cancelled. Covers the child form, inline editing, the delete button and the add-document path.
  • dffs_repeatingSection_loaded_callback(elementId, items) — already available, now documented and in the editor autocomplete.

Custom JS API reference →

Changes

  • Managed metadata fields load faster on large forms — forms with several managed metadata columns now share a single set of term store queries instead of each field querying separately. On a large form — particularly one where the same column appears on more than one tab — this removes most of the requests made while the form loads, and with them the delay and the throttling they could cause. No configuration is needed.
  • Restore points can be created after a save conflict — if someone else saves the same form configuration while you are editing it, you now get the Save Conflict message and can still use Create a restore point to keep your changes before reloading. The restore point contains your unsaved changes while the live configuration keeps the other user’s; after reloading, use Restore under Stored restore points & backups to bring yours back.
  • Restore points: the AI prompt is attached to the right one Enterprise / Pro add-on — a restore point created by hand no longer shows an AI prompt left over from an earlier run, and AI restore points show the prompt they were created for rather than the previous one. An AI restore point is now created only when you actually apply a response: reading one and declining it, or downloading it as JSON, no longer leaves one behind. If the restore point cannot be saved, the response is not applied and the reason is shown. Restore points created before this update keep the prompt text they were stored with.

Bug fixes

  • Applying an AI response that returned a complete configuration without a settings section could overwrite the form’s Misc settings with an empty set Enterprise / Pro add-on — such a response now leaves the existing settings untouched.
  • vLookup and Repeating Section — forms opening on another site Professional & Enterprise — a vLookup set to add new only opened its form without a folder path, which for a document library meant uploads targeted an invalid location (existing configurations are corrected automatically); adding a document through a vLookup pointing at a library in another site collection failed silently; when a vLookup opened a form for a list on another site, Person and Group columns searched the wrong site, append-only comment history and image thumbnails did not load, and a Cross-list write rule action given a target as a path resolved it against the wrong site; and a Repeating Section whose child list is on another site searched the wrong site in Person and Group columns.
  • Repeating Section parent link Professional & Enterprise — the field was described as accepting a Lookup or Number column; Number was never supported, and it now correctly reads Single line of text or single-value Lookup. Multi-value Lookup columns are no longer offered, since SharePoint cannot filter on them and a section using one could never load its rows. And a text parent link whose value contains an apostrophe (O'Brien) loaded no rows.
  • Tabsets in vLookup child forms opened in a side panel Professional & Enterprise — a sticky tab control strip no longer drifts sideways when the window is resized; resizing no longer scrolls the form downwards a step at a time; form content no longer scrolls over the panel’s header or its Save/Cancel footer, and a sticky tab row comes to rest just below the panel header instead of behind it; and the panel size menu in a child form’s header now works on forms whose vLookup configuration has no panel size set.
  • Sticky tabsets — a sticky tabset now pins and releases while scrolling a form open in a side panel, where previously it only responded when the window was resized. On narrow screens, a tabset using separate tab controls now falls back to the tab menu instead of leaving no way to switch tabs. And column sizes now follow their breakpoints as the window is resized, rather than only when the form is opened.
  • Configuration Professional & Enterprise — a repeating section had no id on the rendered element, so it could not be targeted from a rule or from Custom CSS. The vLookup element id was not shown until the web and list had finished loading, and stayed hidden if the target list could not be reached. Highlight matching elements did not match an element id pasted with its prefix — only the id on its own. And one uploaded document could report two adds through a vLookup configured with prefill values.
  • Rule Debug — grouped conditions now show their grouping Professional & Enterprise — a rule whose conditions are grouped was traced as a flat list: the group’s own row appeared after its members, nothing linked a member to the group it belonged to, and the operator joining the rule’s top-level conditions was not shown at all. With more than one group the output could not be read back at all. The condition list is now drawn the way the rule is configured — the operator first (“Any of”, “All of”), then the conditions under it, with each group’s members indented beneath the group and its operator. The Match column is colour-coded, and the Type column has been removed since the nesting now shows it. Console output gains an indent per level; its columns are unchanged.

2.112 September 2026

A large release: form tests, a form bundle a third smaller, seven behaviour changes worth reading before you upgrade, and a long list of rule accuracy fixes.

Behaviour changes — read before upgrading

Eleven changes below alter what an existing, untouched form does or how it looks. Seven are fixes to behaviour that was inconsistent or impossible to work around; the last four are appearance, and are grouped at the end.

Three of them share a single root cause, and it is the one to know about: each form now acts on itself. Where a parent form and a form opened on top of it in a vLookup panel could previously act on each other, they no longer can. If a configuration has been leaning on that crossover — knowingly or not — this is the group to check.

  • An empty number field no longer satisfies a numeric comparison. A rule using greater than, less than, greater or equal or less or equal treated an empty field inconsistently — sometimes as zero, sometimes as no value — and which you got depended on how the form had been loaded, not on anything you configured. An empty field now fails every numeric comparison. If a rule like “Amount is greater than -1” was written to catch items not yet filled in, use the is empty operator instead.
  • Conditional formatting now compares values the same way rules do. It had its own comparison logic and disagreed with the rule engine on the same data — a number holding 5 did not match a formatting rule written as "5", and relational comparisons sorted text alphabetically, so "10" counted as less than "9". Formatting rules that never seemed to work may start working, which means rows that were previously unformatted can now pick up a colour.
  • A quoted number or true/false passed to “Run a custom function” stays text. The rule action Run a custom function, which calls a function you have written in Custom JS, stripped the quotes from a quoted number or true/false argument and passed it as a number or a boolean instead — myFn("42") arrived as the number 42, and there was no way to pass the text "42" or "true" at all. A quoted argument now arrives as text; unquoted ones are still converted. A function receiving a quoted number or true/false value now gets a string — if it does arithmetic on it, or compares it with ===, it needs updating.
  • Show element gives an element back the layout it had. Showing a row — or anything laid out as a flex or grid container — used to hand it back arranged differently from how it started.
  • A rule in a vLookup child form no longer reaches the parent form behind it. Show and hide element searched the whole page, so a class name existing in both forms meant the child’s rule also restyled the parent. Give the parent its own rule if it needs one.
  • A form’s custom wrapper class now goes on that form. For a form opened in a vLookup panel the class landed on the parent and never on itself, so Custom CSS written against it styled the wrong form or appeared not to work.
  • Grouping headings in a lookup tree view can no longer be chosen. In a tree view described by the JSON form with a root column, the grouping headings were offered as choices even though they are values rather than items — and choosing one stored a reference nothing could match. Items filled in that way still hold the unusable value and need setting again; nothing rewrites stored data.
  • The vLookup “Add new item” button is now a proper button. It was drawn borderless, which above a table put it close enough to the column headings to read as one of them. It now looks like the repeating section’s Add row button — bordered, with the same plus icon — so a form using both no longer shows two different-looking buttons doing the same job. Its position does not move: existing vLookups keep the button above the table.
  • Repeating sections and related items now line up with the rest of the form. Both sat about 5px further left than the fields and vLookups around them, which was invisible until the buttons started matching. Every form element now shares the same inset.
  • A themed form now styles the repeating section and related items add buttons too. Only the vLookup one carried the class the Theme Builder styles, so a form with restyled buttons showed one styled and two stock. All three now match — which means those two buttons can look different after upgrading, in the same way the rest of your buttons already do.
  • Repeating section and related items tables now follow your site theme. Their header row and totals row were filled with a fixed grey while a vLookup’s followed the theme, so two tables on the same form disagreed — and the grey stayed grey whatever theme the site used. All three now take the theme’s own background, and their header and totals rules are the same weight. Those rows look lighter after upgrading on a site using the default theme, and pick up the site’s colour where a theme sets one. What marks them out is unchanged: bold text, and a line above and below.

New features

Form tests Professional & Enterprise

A new Tests tab beside Rules lets you record test cases against your own configuration, so you can change a rule and know in seconds whether the other thirty still behave, instead of clicking through the form to find out. A test case is set these values, then check that: whether a named rule fired, whether a field became shown, hidden, required, optional, read-only or editable, whether a field holds a particular value, whether a tab appeared, whether the form passes required-field validation, or whether a rule would have run an action such as sending its email. Results are a plain green/red list, and expanding a failure shows the check that broke along with the same rule condition table the Rule Debug panel produces — so a failure reads “expected Status == Rejected, actually found Draft” rather than simply “did not match”. Read the guide →

Running tests never touches real data. Rule actions that reach outside the form — send email, write to another list, trigger a Flow, call a webhook, show a message box, and run custom JavaScript — are recorded rather than executed, and listed in the result under “Actions that would have run”. So you can test that rejecting a request would send the notification without anyone receiving one. The item is never saved, and the form is returned to its starting state when the run finishes — including the data a save would write, so running a test and then pressing Save cannot save test values by accident.

  • Record a test instead of writing one — press Record a test and Modern DFFS switches to the form preview and starts watching. Fill the form in the way a user would, press Stop and review, and you are shown what changed: the values you entered, and a checklist of what the form did in response. Untick anything you do not want checked, name it, and save. A value a rule worked out for you is ticked; a value you typed yourself is offered unticked, because checking the thing you just entered proves nothing.
  • Values are entered with the column’s own control — a choice column offers its own choices, so a test cannot fail on a typo; a Yes/No column offers a toggle; a person field’s box states what it accepts — an email, a login name, an id or a group name; and free text is the fallback for columns whose valid values cannot be known in the configuration.
  • Person fields — check that someone was filled in, without naming them — the “A field has a value” check offers four comparisons: equals, is empty, is not empty, and is the current user. “Is not empty” is the one you usually want for an approver a rule fills in — the rule filled the approver in, not the rule filled in Bob. And when you record a test where a rule assigns the current user to a person field, the recorder proposes is the current user rather than your own name — a test naming you would pass for you and fail for every colleague.
  • Custom JavaScript is never run by a test — for a rule that decides whether it matches by calling a custom function, you tell the test what that function should return, and the editor lists only the function names your form’s rules actually use. Your function may call SharePoint, read the clock or check the current user, and running it would make the test depend on things it does not control. It also lets you test both answers rather than only the answer the function gives today.
  • Pin the date, run tests on save, and spot tests that point at deleted rules — a test can pin the date it was written for, so a rule that compares against today keeps giving the same answer next month. Tests can run automatically before the configuration is saved, where failures warn rather than block. And a check against a rule the form no longer has says so explicitly, which otherwise looks identical to a rule that simply did not fire.
  • Tests travel with the configuration — they are stored with it, so they survive export, import and promotion between DEV, UAT and PRD. Each of New, Display and Edit is its own configuration with its own rules, so its tests belong to it.

Custom JS

  • New Custom JS function: dffs_getVisibleFields() Professional & Enterprise — Custom JS could already ask which fields the rules had made required, but not which they had left visible. Answering “is everything the user can see filled in?” meant hard-coding a field list and keeping it in step with the form by hand — which quietly went wrong the first time someone added a tab or a hide rule. A field on a background tab counts as visible, since the user reaches it by clicking a tab. Passing true adds an optional check of the rendered page, which also catches fields hidden by a show/hide element rule action or by Custom CSS — call that form from dffs_ready or later. Custom JS API reference →

Rule diagnostics

  • Rules that can never fire, or that quietly skip part of what they say, are now flagged — a rule can name a column that has since been deleted from the list, and nothing reported it. The rule builder now distinguishes the two cases, because they mean opposite things: NEVER FIRES, where a condition names a deleted column so the rule is dormant and has not run at all; and MISSING FIELD, where an action names one so the rule still runs and silently skips that part. The second is the one that costs you quietly — no error, no warning, and a form that stopped enforcing something it used to. A Clean up missing fields button removes the dead references from every rule’s actions at once, and each affected rule has its own. Dead conditions are flagged but left alone on purpose: removing one would let a rule that has been switched off start firing, possibly for the first time in months, which is a decision to make with the rule in front of you.

vLookup Professional & Enterprise

  • Show another field from the item a lookup column points at. A vLookup table could only show columns belonging to the list it queries, so a table listing order lines could show which product each line refers to but nothing about that product. A single-value lookup column now offers + Show another field, listing the fields of the list it points at; the one you pick becomes a read-only column in the table — a product’s unit price, a customer’s phone number, a supplier’s status — without adding anything to either list. It costs no extra request: the value is fetched by the query the table was already making.
  • Calculate a column from the other columns in the row. Add calculated column… opens a formula builder — a title, a formula, live validation, and the full function reference — using the same [InternalName] formulas as repeating sections. A formula can reference ordinary columns, the derived columns above, and other calculated columns, so [Quantity] * [Unit price] works and a second formula can build on the first. Calculated columns can carry a Sum, Average or Count in the totals row and can be colour-coded with conditional formatting, exactly like a real column. Nothing is written back to the list — the value is worked out as the table is drawn, and it keeps up with a row while that row is being edited inline.
  • Both kinds of column print with the rest of the form in Save as PDF. Neither can be sorted, grouped or filtered on, because neither exists in the query that does the sorting — the same limitation repeating-section columns have.
  • vLookup columns can now show data fetched from somewhere else — a vLookup column’s customizer function formats what the query returned, and has to hand its HTML back on the spot, so a column that needed a value from another list or a service could not be built at all. Writing the function as async did not help — the cell showed [object Promise]. A new prepare function, named on the vLookup’s Table tab, is where that lookup now goes: it is handed every row the query returned and the table waits behind its loading spinner until it finishes, so the customizer still runs the instant the table draws — with the data already in place. Because it receives the whole table at once, twenty rows needing a name from another list cost one request rather than twenty.

vLookup guide → · Custom JS API reference →

Changes

  • New setting: Position of the add button Professional & Enterprise — choose whether the Add new item / Add row button sits above or below the table, on both vLookups and repeating sections. New elements default to below the table, next to where a new row appears; existing vLookups keep the button where it is and only move if you change the setting. In a vLookup it is on the Add new tab; in a repeating section, under Behavior.
  • A vLookup column with no field is easier to reach. A column that renders purely through a customizer function has always been supported, but the option to create one was offered only when changing an existing column — so the way to get one was to add a real column and immediately swap it. It is now offered when adding a column too.
  • A brand new vLookup shows its Configure button. An unconfigured vLookup displayed only a line of text pointing at the element menu, in the one situation where configuring it is the only thing to do.
  • Formulas are edited in the formula builder. Changing a repeating section’s or a vLookup’s calculated column reopens the builder, so the function reference and the column list are there when you edit a formula and not only when you write one. The list of columns you can reference is now clickable — pick one and it is inserted into the formula at the cursor.
  • Dynamic content in column labels, titles and totals affixes. A vLookup’s Custom field label and totals Prefix/Suffix, and a repeating section’s Display title and column Prefix/Suffix, now offer Add dynamic content with [[variable:NameOfVariable]] — useful for a heading or a currency symbol that has to follow a Custom JS variable, most often for multi-language forms. Only variables are offered here, deliberately: these are written once for the whole table rather than per row, so a field-value token would have no row to resolve against.
  • Custom CSS no longer affects the configuration screen — Custom CSS is loaded in the configuration so you can preview your form, but it applied to the whole page, so a broad selector reached the configuration itself. Write [role='tab'] { background-color: red; } and every configuration tab turned red. Custom CSS now applies only inside the Preview form view, and on the real form exactly as before. Nothing changes for the form your users see.
  • New Custom CSS class .dffs-readonly — added to a field wrapper when the field is read-only, whether a rule made it read-only or it is on a display form. It works like the existing .dffs-required and appears in the Custom CSS autocomplete beside it. Previously the read-only state was only visible as disabled on the inner control, which differs by field type and disappears entirely on display forms.
  • Every form loads about a third less — the file every DFFS form downloads has gone from 8.1 MB to 5.4 MB, roughly 2.6 MB less on a first, uncached load. One stray import was pulling an entire control library into the bundle, none of which DFFS uses; and DFFS was shipping two versions of Microsoft’s Fluent UI component library at once, plus two copies of one of them, where there is now one version in one copy. Fewer “Theming value not provided” warnings in the developer console come with it — most belonged to controls DFFS never renders. Any that remain are normal and harmless.
  • Location fields are shown read-only — the modern Location column now displays its stored value as text on all form types instead of offering a picker. The picker never actually worked: the Microsoft service it resolves against stopped issuing the token it needs, silently, so typing produced no suggestions and two console errors. There is no fixed version to move to, and rebuilding it would require every customer’s tenant administrator to approve an admin consent at install time. Existing values still read correctly. This only affects lists that already carried a Location column — DFFS has never created them.
  • Form columns are now laid out with CSS grid — the 12-column form layout is sized with a more modern mechanism built for the purpose. This is intended to be invisible, and every column width combination and screen size was checked against the previous behaviour. It is mentioned because it touches the layout every form uses. One improvement comes with it: unusually wide content in a column — a long unbroken string, a wide table — now stays inside its column instead of stretching it.
  • Updated components — the Jodit rich text editor, the SharePoint control library behind the people picker, taxonomy picker, date/time picker and tree view, and the code editor used for Custom JS and Custom CSS have all been updated. Formulas are unaffected: every existing formula evaluates exactly as before.
  • Dialog buttons now follow your theme Professional & Enterprise — buttons in a dffs_showModal message box already picked up the button styling from your theme, but the ones in a dffs_showDialog message did not: a form with restyled buttons showed a stock blue OK button the moment a dialog opened. Both now carry the same classes. A dialog can therefore look different after upgrading — it will look like the rest of your form, where before it did not. Both functions also take optional okBtnClassName and cancelBtnClassName values, appended to the standard classes rather than replacing them, for the one dialog that needs a button unlike every other. And typing dffs_showDialog in the Custom JS editor now expands to its full list of options instead of just title and body.

Bug fixes

  • Snapshots are now listed in date order — the Snapshots table in Browse configurations was ordered by when each row was written rather than by the date it shows, so backups migrated from an older list — written last but genuinely the oldest — sorted above newer snapshots. On lists with more than 100 snapshots the newest could also be missing from the table entirely; the panel now loads the most recent ones.
  • Delete could be shown to someone without permission to use it — a rule action that shows or hides the form’s buttons only checked the rule, not the caller’s permissions, so a rule revealing the Delete button revealed it to everyone the rule matched. The button now requires both. Nothing changes for users who already had the permission.
  • Formulas: = inside a text value is no longer treated as a comparison — the formula language accepts Excel-style single = for equality and converts it to ==, but the conversion was applied to quoted text as well, so CONCATENATE("Total=", [Sum]) produced Total==. The validator reported the formula as valid, so the wrong value only appeared at runtime. Quoted text is now left alone, and a real comparison in the same formula still works.
  • The AI tab no longer creates duplicate columns Enterprise / Pro add-on — applying the same AI response twice now creates nothing the second time. Suggested fields are matched against the list’s existing columns by both internal name and display name, so a column you already have is left alone instead of being recreated under a suffixed name.
  • Suggested lookup columns become text fields Enterprise / Pro add-on — DFFS does not create lookup columns from an AI response. A suggested lookup is created as a text field you can wire up afterwards, and both the confirmation dialog and the summary tell you it happened, rather than the step failing part-way through.
  • A field that cannot be created no longer costs you the response Enterprise / Pro add-on — each column is created independently, and a summary afterwards lists what was created, what already existed and what failed. The configuration is imported either way, and if every proposed field already exists the confirmation dialog is skipped and the import simply runs.
  • The code editor could scramble your code when deleting several lines at once — in the Custom JS and Custom CSS editors, deleting a block of lines from the middle of a long script could occasionally fail and leave the code on screen garbled. This was a bug in the third-party code editor component Modern DFFS uses, now updated to a fixed version. Editing long scripts is reliable again, and a rare error when using Replace all in the editor’s search panel is fixed by the same update.
  • A harmless console error on forms has been removed — some of the form controls Modern DFFS uses come from the PnP community control library, which sent an anonymous usage ping to a community server every time one of them was used. That server is no longer running, and many organizations block it outright, so the browser’s developer console filled with failed-request errors that appeared to come from Modern DFFS. The ping is now switched off. Nothing about how forms work changes — but anyone who opens the developer console will no longer see errors that suggest something is wrong.
  • Pattern validation is no longer shown when designing the display form Professional & Enterprise — pattern validation for Single line of text fields was offered in the field properties panel on the display form, where it could not do anything: the field is read-only and there is no save to validate. The setting is now hidden there, matching the other text-field enhancements, and is configured on the New and Edit forms as before. Existing forms are unaffected.
  • A group-membership rule could evaluate backwards — a condition testing whether the user is in a group could be evaluated as is not in, showing a field to everyone except the intended group. Only conditions where the operator had never been stored were affected, so a rule built and saved in the configuration screen never was — but one generated by the AI Assistant, imported from a file, or hand-edited could be.
  • Showing and hiding elements by class did nothing when the form loaded — the rule worked when triggered later by a field change, but could do nothing on load; a form opened in a vLookup panel failed almost every time. Rules now wait until the form is on screen, and targeting by class retries the way targeting by element id already did. A class matching nothing is now reported in the browser console instead of failing silently — if one appears on a form you thought was working, that action has been doing nothing for as long as it has existed.
  • Reopening the configuration no longer stacks up copies of itself — closing the configuration screen did not take it down, so each reopen left another copy running invisibly. Over a long design session that meant Ctrl+S saving more than once, stray “unsaved changes” warnings about a configuration already closed, and a browser that slowly got heavier. Forms being filled in by end users were never involved.
  • Quick save failed after pasting an image into a new form — pasting an image into a rich text field on a new form and then using Quick save produced an error. Ordinary Save worked, and so did adding the image as an attachment — that one combination broke. The same underlying mistake also left created by and created empty in an email sent by a rule on save of such a form.
  • The AI Assistant no longer renames two settings — two settings shared an internal short name, so a field’s label width came back as a signature field’s line width, and a signature field’s allow multiple signatures came back as a tab set’s multi-step setting. If you have used the AI Assistant on a form with a signature field or a custom label width, check those settings are still what you expect.
  • The Rule Debug button was stuck behind a vLookup panel — unreachable at exactly the moment it is most useful. Both the button and its panel now stay in front.
  • Printing no longer picks up another form’s styling — with a vLookup child form open, whichever had drawn most recently decided the styling used for Print and Save as PDF. Each form now prints as itself.
  • The signature buttons now show an icon — Sign, Re-sign and Add signature requested an icon that does not exist and rendered with an empty gap.
  • Smaller fixes — a background image in a field’s custom style now works (any value containing a second colon was cut short); an empty conditional formatting configuration no longer errors while drawing the field; images pasted into a rich text field are stored byte-for-byte rather than a byte or two longer; the environment banner names the right environment on sites whose addresses are prefixes of one another, such as …/sites/Case and …/sites/CaseDev; the check on reusable content links now compares addresses properly rather than as text, so one merely resembling your tenant’s can no longer pass (content already in the library is not re-checked); opening the Rules tab no longer counts as changing the configuration; and switching a condition to a trigger that takes no operator clears the old one.
  • Related items in Save as PDF Enterprise / Pro add-on — the printed table now shows the direction of each relation, incoming or outgoing, matching the form. And when Group rows by list is enabled, the printed output is grouped the same way as on screen, with a heading naming the list above each group and that list’s own columns. Previously the printed table was flat and did not identify the list at all.

2.0.129 August 2026

A maintenance release: licensing for part of an organization, a proper read-only view when you open an item from version history, easier rich text editing, and a set of fixes across the form builder, vLookup printing, and lists that use folders.

Changes

  • Division licensing — Modern DFFS can now be licensed for a single division, business unit or subsidiary inside a tenant, instead of the whole organization. Two models are available: a seat license, where you activate each site yourself up to an agreed number, and a prefix license, where the sites covered are written into the license when it is issued. The configuration screen names the licensed division, so it is clear which part of the organization a license belongs to. Contact us if you want to license part of your organization rather than all of it.
  • OEM licenses can now be locked to a tenant — an optional safeguard so a license cannot be used outside the organization it was issued to. Existing OEM licenses are unaffected.
  • Version history now shows the version you picked — choosing “View” on an earlier version in a list’s version history opened the Modern DFFS form but still showed the item’s current values. It now shows the version you selected, as a clean read-only page listing the fields in your display form’s order, with a banner naming the version, when it was changed and by whom, and a button to go back to the list.

    Because SharePoint only keeps history for a list item’s own columns, repeating sections, vLookup tables, related items and attachments are not part of a version and are left out rather than shown with today’s data. Form rules and custom JavaScript do not run on this page, so simply looking at an old version can never trigger an email or any other action.

  • Easier rich text editing — you no longer have to find and click the small pencil icon to edit a rich text field. Click anywhere in the field and the editor opens. Links inside the field still work normally, and you can still select and copy text without opening the editor. This applies to New and Edit forms — Display forms and read-only fields are unchanged.
  • The rich text editor now has Save and Cancel — replacing the old “Close panel” button. Cancel, the X, and Esc discard your changes, and you will be asked to confirm if you have edited anything. Clicking outside the editor no longer closes it, so a stray click cannot lose your work. Note that “Save” saves into the form — the value is written to SharePoint when you save the form, as before.
  • Full-width rich text editing — the rich text editor opens as a side panel, which can feel narrow on a large screen. A new button next to the editor title expands it to the full width of the browser window, and your choice is remembered for next time.
  • Copied rows and columns can now be pasted properly — copying a row or a column with all its contents always worked, but there was no correct place to paste it back in. Now the plus icon above and below a row offers Paste copied row, and the plus button at the end of a row with free space offers Paste copied column. The column Add element menu no longer lets you drop a row inside a column, which was never a valid layout. As before, you can copy from one form to another — and if you copied fields, the destination form needs fields with the same internal names. Pasting the same element twice no longer causes problems: each paste now gets its own fresh element ids.

Worth knowing: Save and Cancel reverses what the rich text panel used to do. The old “Close panel” button always kept your edits; closing now discards them unless you click Save.

Bug fixes

  • Licensing a site now takes effect without closing the browser — if an administrator licensed or activated a site while you had a form open, you previously stayed on the unlicensed experience until every tab was closed. The license is now re-checked, so a page reload is enough.
  • Lists that use folders now work properly — on a list with folders turned on, two things were broken. Creating an item from inside a folder failed when you saved it, because the folder was sent to SharePoint as a partial path it could not resolve. And opening an existing item that lives inside a folder reported “This item could not be found. It may have been deleted.” — the item was always there, but the query that loaded it only looked in the list’s root folder and never inside folders. Both are fixed, and items in the root of the list are unaffected.
  • vLookup customizer functions now run when printing — a vLookup column with a customizer function printed the raw underlying value through Save as PDF, even though the form showed the customized output. It now prints exactly what the table shows.
  • vLookup footer totals now print — count, sum and average totals appeared in the form but were missing from the printed table. They now print, formatted exactly as on screen including currency and decimal settings. Printed vLookup rows are flat, so the footer is a single grand total rather than the per-group totals a grouped table shows.
  • vLookup grouping and sorting on fields starting with an underscore — setting Connect to list > Group by (or sorting) on a column whose internal name starts with an underscore, for example _DFFSID, broke the query so the table did not load. Grouping, sorting and footer totals now all work on those columns.
  • Send email rules always use Power Automate FLOW — the AI Assistant could create email actions set to the old, deprecated sending method, which then failed when the rule ran. New and edited email actions now always use Power Automate FLOW, and older rules saved before this setting existed no longer open showing the deprecated option. Note that scheduled sending is only available with Power Automate FLOW.
  • Fixes for sites not using the Jodit editor — empty rich text fields no longer collapse to a thin strip and now show their placeholder text, and the formatting toolbar no longer overlaps the top of the text area.
  • “Add column” now works on every row — the plus button that adds a column to a row was only shown on rows sitting directly in the form’s outer grid, so rows inside a tab set or a nested grid appeared to be stuck with the columns they had. It now appears on any row with free space left.
  • Clearer copy confirmation message — the message shown after copying an element said to hover a plus icon; you actually have to click it. It now tells you which plus icon to click and which menu entry to pick for the kind of element you copied.
  • The delete confirmation highlight now covers the whole element — when you choose to remove an element, the red highlight behind the confirmation dialog stopped short of the element’s grey title bar, which made it unclear exactly what was about to be deleted. The highlight now covers the element completely.
  • Spacing fixes — read-only multi-choice fields and custom row bodies no longer sit flush against their borders.
  • Translation fixes — the send email rule error message is now translated in Czech and Slovak, and the Norwegian version quotes the “Send email using” setting by the name actually shown in the interface.

2.09 August 2026

The 2.x line. Everything below arrived with this release — the sections are a feature overview rather than a change list, because 2.0 replaced v1.x rather than extending it.

License tiers

Modern DFFS 2.0 introduces three tiers so you only pay for what you need:

TierWhat you get
EssentialsCore form building — field layout, visibility rules, basic validation, and standard field operations.
ProfessionalEverything in Essentials, plus advanced rule actions (send email, calculated fields, write to another list), multi-language support (MUI), Custom JavaScript, and Custom CSS.
EnterpriseEverything in Professional, plus Theme Builder, AI Assistant, Print to PDF, the Admin tool, and Reusable Content. All except Reusable Content are also available as individual add-ons on the Professional tier.

Already have a Modern DFFS license from before 2.0? It carries over as a Professional license — nothing to buy, no new code to enter — so the whole Professional feature set below is yours, including everything new at that tier. What needs a new license is what 2.0 added above it: the add-ons (AI Assistant, Admin tool, Print to PDF, Theme Builder) and the Enterprise features (Reusable Content and tenant-wide centralization). See pricing →

Try before you buy. A time-limited Trial upgrade temporarily raises your active tier to Professional or Enterprise so you can evaluate higher-tier features before purchasing. A banner in configuration mode shows the remaining trial days.

Throughout this page: items with no badge are available in all tiers. Professional & Enterprise requires a Professional or Enterprise license. Enterprise / Pro add-on is included with Enterprise and can also be bought on its own on top of a Professional license — that covers the AI Assistant, the Admin tool, Print to PDF and Theme Builder. Enterprise on its own means Enterprise-only, not purchasable as an add-on: that is Reusable Content and tenant-wide centralization, which need an Enterprise license.

Flagship features

These are the headline additions in 2.0. Each has a full guide.

  • AI Assistant Enterprise / Pro add-on — Build, edit and review form configurations from plain-language prompts. Bring your own API key (Claude, OpenAI, Gemini, Mistral, Grok, or Groq) or route requests through an organization-wide Enterprise relay. AI Assistant guide →
  • Reusable Content Enterprise — Store shared HTML blocks, Custom JS and Custom CSS in a central (or local) library and insert them into any form in the tenant. Content stays live — edit the source once and every form that references it updates. Reusable Content guide →
  • Related Items Professional & Enterprise — Link list items to one another with typed, bidirectional relationships (Related to, Blocks, Blocked by, Duplicates). The backing list is provisioned automatically — no manual setup. Related Items guide →
  • Repeating Sections Professional & Enterprise — Add, edit and delete related child-list items inline, in a table right on the parent form — with calculated columns, a totals row (Count / Sum / Average / Min / Max), lookup-derived columns (surface extra fields from a selected lookup item, e.g. a product’s unit price), a per-column prefix/suffix (e.g. currency symbols or units) that displays on values and totals without affecting the underlying maths, auto-updating column titles, and a Custom JS callback. Repeating Sections guide →
  • Compute field value — formula expressions Professional & Enterprise — A new rule action that sets a field from other fields using Sum, Subtract, Multiply, Divide, Concatenate, Date offset, Date difference, or free-form Excel-style formulas (IF, CONCATENATE, ROUND, DATEDIF, and more) with a live syntax validator. Formula Expressions guide →
  • Multi-step / wizard forms — Turn a tabbed form into a guided wizard with fully customizable step indicators (size, color, checkmarks, labels, arrows), linear navigation, per-step validation, and an overall progress bar. The overall progress bar and per-tab completion indicators are available in all tiers; advanced step-indicator styling and wizard options are Professional & Enterprise. Multi-Step Forms guide →
  • Draft auto-save All editions — Partially filled new forms are saved automatically to the browser so users can pick up where they left off. Draft Auto-Save guide →
  • Signature capture & co-signing Professional & Enterprise — Collect one or more handwritten signatures on a field, with named co-signers, pen/color options, and image display on the read form. Signature & Co-Signing guide →
  • External REST data source Professional & Enterprise — Drive dropdown and autocomplete fields from any HTTP endpoint, with token-based dynamic filtering and optional authentication. REST Data Source guide →
  • Theme Builder Enterprise / Pro add-on — Visually brand your forms — colors, typography, spacing, buttons, tabs, modals — then save to Custom CSS or export and reuse across forms. Theme Builder guide →
  • Print to PDF Enterprise / Pro add-on — Export forms to branded PDFs (or paper) with an optional cover page, custom header/footer, page numbers, and control over which fields appear. Every form element is included — repeating sections (with totals), related items, reusable content and HTML/rich-text blocks — and content hidden by rules is left out. Image attachments (photos, screenshots) render inline as actual pictures rather than a filename link (configurable, default on, with a max-height setting). Logos accept a per-image height via the URL (logo.png?h=100), the file-name template also names the browser’s Save-as-PDF dialog, and solutions sharing one config across sites can patch the PDF settings per site from Custom JS with dffs_setPdfSettingsOverride({…}) — with no flash of the wrong state while per-site settings load. Enhanced fields print as what you see rather than what is stored: star ratings print as stars, signature capture prints the actual signature image(s), and custom render function fields print their live-rendered output. Custom JS can hook the export: dffs_PrePrintAction(ctx) can mask or reformat values for the printed document only — the form on screen is untouched — or block the export entirely, for example until a request is approved or signed; dffs_PostPrintAction(ctx) runs when the print dialog closes, for logging. The PDF document is produced only by the Save as PDF button — a plain Ctrl+P never prints it. Print to PDF guide →

Other new features

All tiers

Forms & layout
  • Form layout density — Switch the rendered form between Compact, Comfortable (default) and Spacious spacing, saved per form (New, Edit and Display can each differ).
  • Hide fields with no value in display form — A toggle that hides empty fields (and tabs containing only empty fields) when viewing an item.
  • Custom placeholder text on fields — Show placeholder text on text, number, currency, choice, date, person and managed-metadata fields; supports dynamic content, with multi-language placeholders on Professional & Enterprise.
  • Default field label position — Set a default label position (top, left, or hidden) for all fields on the form.
  • Dynamic content — Variables and field values can now be used in field tooltips, custom field labels, and message box titles.
  • Tab labels & group headings — Add labels and group headings to individual tabs in a tab set.
  • Tab completion indicator — Each tab can show a green checkmark when its required fields are filled, or an orange warning when they aren’t — updating as the user types.
  • Tab inline styling — Apply inline CSS to all tabs at once or to individual tabs independently.
  • Container classname on HTML & Rich text elements — Previously available on rows only.
  • Custom labels on more elements — Organizational labels (shown in configuration mode only) can now be added to grid, column, HTML, Rich text and vLookup elements.
  • Max-width for picture fields — New max-width option for Hyperlink/Picture fields in Picture mode.
  • Easier rich text editing — Click anywhere in a rich text field to open the editor; you no longer have to find the small pencil icon in the corner. Links inside the field still follow normally, and selecting text to copy it doesn’t open the editor. New and Edit forms only — display forms and rule-locked fields are unaffected.
  • Save and Cancel in the rich text editor — The editor panel now has explicit Save and Cancel buttons in place of the old “Close panel” button. Cancel, the X and Esc discard your edit, with a confirmation prompt if you actually changed something; an untouched field just closes. Clicking outside the panel no longer closes it, so a stray click on the form behind can’t lose your work. “Save” saves into the form — the value reaches SharePoint when you save the form, as before. One useful side effect: images pasted into the field are no longer uploaded as attachments if you Cancel. Rich Text Fields guide →
Form builder
  • Easier drag and drop in long forms — dragging a form element now shows a “Hold here to scroll up / down” band at the top and bottom of the form area. Hold the element over a band and the form scrolls that way — faster the closer you get to the edge — so moving an element to a distant part of a tall form no longer means lining the pointer up exactly with the edge of the scroll area. A band fades out when there is nothing left to scroll in that direction, and neither band blocks a drop on the elements underneath it.
  • Search & highlight — Search your form configuration for keywords (e.g. text inside HTML sections); matches are highlighted in place.
  • Search by item ID — Jump to and highlight an element by its item ID from the rules tab and the form builder.
  • Add multiple fields at once — A Select multiple toggle lets you check several fields, reorder them, and add them in one go.
  • Fields & list settings tab — A new tab lists every field in the list and links to list settings.
  • Visual indicator on configured elements — Elements with container styling, a container classname, or a set width show a small marker in the builder.
  • Last saved indicator — The configuration panel shows “Last saved [date-time] by [editor]”.
Backups & restore
  • Restore points & backups — Manual and automatic restore points are now stored in a separate snapshot list, keeping your main configuration list lean and reliable. A dedicated Stored restore points & backups section in the import/export panel lets you restore (full, layout-only, or rules-only), delete or compare each one, and a one-click action migrates any existing legacy backups into the new list.
Rule debugging
  • Clearer rule debug — “Debug this rule” now shows each rule’s conditions as a compact table with a ✓/✗ result. A new in-page Rule Debug panel shows the same information inside the running form for anyone who prefers not to use the browser console.
Classic import
  • Cascading dropdowns — The Classic-to-Modern importer now attempts to recreate cascading dropdown configurations.
Saving & integration
  • Control Power Automate flows from DFFS saves — Add an optional text column named DFFSSaveType to your list and DFFS records how each item was saved: save, saveandedit, quicksave or autosave. Use it in a flow trigger condition — e.g. @equals(triggerOutputs()?['body/DFFSSaveType'], 'save') — so your flows no longer fire on every quick save and auto save, and only run when the user actually finishes and saves the form. As with _DFFSID, the field is only used if it exists; lists without it are unaffected. The Misc tab tells you whether the column was found in the current list. System fields reference →
For developers (Custom JS)
  • dffs_overrideMandatory — Programmatically override mandatory field validation. The override now runs alongside (not instead of) the rule engine’s own required-field logic, and can be cleared at any time with the new dffs_resetMandatoryOverride to fall back to whatever the rules currently require. Rule-required fields keep their required-asterisk even while an override narrows what actually blocks save, and new dffs_getRequiredFields / dffs_getRequiredFieldsOverride let Custom JS read the base and override lists.
  • dffs_PreDeleteFunction — Runs after Delete is clicked but before the confirmation dialog; return false to cancel.
  • dffs_formcontext — New read-only itemId and itemData properties, useful with vLookup and child items.
  • dffs_showModal — okBtnFn / cancelBtnFn callbacks no longer close the modal when they return false, and the modal header, body and footer now have addressable id attributes.

Professional & Enterprise

Form elements
  • vLookup (add new only) — A vLookup variant that shows only the “Add new item” button (with field prefilling) and hides the related-items table — for prefilled child-item creation without displaying a table.
  • Inline editing in vLookup fields — Edit individual vLookup fields in place without opening the full item form (text, multiline, date, single choice, single lookup, yes/no, number, currency).
  • Inline Power BI tile — Embed a Power BI report or tile in a form, filtered to the current item via tokens.
Field enhancements
  • Pattern validation — Enforce an input pattern on single-line text fields (Email, URL, Number, Letters, Alphanumeric, or a custom regex).
  • GPS coordinates input — Capture latitude/longitude directly in a text field.
  • Barcode / QR scanner — Scan barcodes and QR codes into a field using the device camera; choose which formats to accept.
  • Star rating on Number fields — Replace the number input with a configurable 1–10 star control.
  • Restrict date range — Limit selectable dates on Date fields using fixed, relative (offset from today or another field), or formula-based bounds — available as a field setting, a rule action, and via Custom JS.
Rules & actions
  • Write to other list — A rule action that writes values to fields in another SharePoint list after the form is saved.
  • New choice-field operators — contains, does not contain, starts with, does not start with, ends with, does not end with (accept free-text input).
Custom HTML & CSS
  • Site theme colors as CSS variables — The current SharePoint theme is exposed as CSS variables (var(--themePrimary), var(--bodyText), var(--neutralLight), …) you can use in custom HTML sections, Custom CSS and Theme Builder values instead of hardcoded hex colors, so forms follow the site theme automatically — including a live theme change. An rgba()-friendly -rgb variant and a --dffs- prefixed alias are provided for every token. Theme Builder guide →
Classic import
  • Custom JS & CSS included — Imports the original Custom JS/CSS (and “load before executing” file references) as commented-out code, ready to be adapted.
  • vLookup import — Import Classic vLookup configurations directly into Modern DFFS vLookup sections.
  • Script-tag warning — Imported HTML sections are flagged if they contain <script> tags or inline event handlers.
Code editors
  • Automatic line wrapping, split-editor and full-screen views, a richer right-click menu (copy/paste and more), and autocomplete for list field names and built-in dffs_ functions.
For developers (Custom JS)
  • CRUD helpers — dffs_spAdd, dffs_spGet, dffs_spGetById, dffs_spUpdate and dffs_spDelete create, read, update and delete items in any SharePoint list (optionally cross-site). All are async and return Promises.
  • Custom render functions — async support — Render functions can return a Promise<string>; a spinner is shown while it resolves. Rendering is also deferred until onload rules have settled, so a function never runs for a field an onload rule will hide.
  • dffs_Post* hooks can hand control back to DFFS — Post-action hooks (e.g. dffs_PostSaveAction) can return false to fall back to default DFFS behavior, and dffs_triggerSave now passes the chosen follow-up action through.
  • Print to PDF hooks Print to PDF add-on — dffs_PrePrintAction(ctx) runs when Save as PDF is clicked and is awaited: sanitize values for the printed document only via ctx.values (the form on screen is untouched, and the sanitized values also feed the cover/header/footer tokens and the file name template), or return false to cancel the export. dffs_PostPrintAction(ctx) runs when the print dialog closes — useful for logging, though browsers don’t reveal whether the user actually saved the PDF, so it fires either way. Print to PDF guide →
  • dffs_showDialog — Show the simple message dialog mDFFS uses internally from your own Custom JS; { title, body } is all it needs. Handy for explaining why a dffs_PrePrintAction blocked a print, since DFFS shows no message of its own when one is cancelled.

Enterprise

  • Enterprise central site — Host a ModernDFFS_Central site that supplies reusable form content, a tenant-wide default theme, global Custom CSS and JavaScript, a managed AI relay, cross-site-collection Related Items and central license distribution — governed once, applied to every form in the tenant. Central functionality requires an active Enterprise license and is enforced every time a form loads: if a site’s license expires or is downgraded it stops using the central site on the next form load, even though the site itself stays in place — and starts using it again as soon as the license is renewed. Nothing is deleted or rewritten in the meantime, so no configuration is lost. Sites that are not on Enterprise never contact the central site at all. The one exception is your internal support contact, which keeps appearing in license banners for any centrally-licensed site even after the license stops validating, so your users always know who to contact. Enterprise overview →  ·  Reusable Content guide →
  • Configuration promotion (DEV → UAT → PRD) — Associate a form configuration with a deployment environment and promote it along a DEV → UAT → PRD path. A banner shows the current environment, and the mapping is shared across the sibling New, Edit and Display forms.

Changes

  • Smarter “save before exit” prompt — Closing the configuration panel now prompts to save only when there are unsaved changes. The browser also warns you before you refresh or navigate away with unsaved edits, so work is no longer lost silently.
  • Longer license-expiry warning — The renewal banner now appears 30 days before expiry (previously 14), giving more time to arrange renewal.
  • Picture fields in Picture mode now display the full-size image (constrained to the container width) instead of a small thumbnail.
  • Flexible root folder paths — Dropdown and autocomplete field configurations now also accept the /Lists/ListName short path in addition to full server-relative paths.
  • Sticky tab sets — Improved styling when the “keep the tab set at the top on scroll” option is used.
  • Renamed menu — “Import / Export” is now “Import, export and restore configurations” to reflect its full scope.
  • Restyled configuration-password prompt and an adjusted loading message on small screens.
  • Professional & Enterprise Expanded in-product documentation in the Custom JS and Custom CSS tabs (including stable CSS classes for theming).

Bug fixes

Fields & display
  • Number and currency fields now respect the configured number of decimal places everywhere they’re shown (read-only display, calculated columns, lookup columns, and vLookup totals).
  • Fixed date/time fields rendering 5px taller than other fields, which gradually pushed adjacent columns out of alignment.
  • Fixed people picker and managed metadata fields being slightly short and shrinking once a value was selected.
  • Fixed clearing a value from an autocomplete field on edit not removing the saved value.
  • Fixed a people picker filled in during the current session not showing the user info card on hover once set to read-only.
  • Fixed downloading an attachment whose filename contains special characters.
  • Fixed an empty rich text field collapsing to a thin strip — shorter than the edit pencil sitting on it — and showing no placeholder text even when one was configured. It now keeps a sensible minimum height and shows its placeholder. Affects sites with “Use the Jodit editor” turned off; both editors now size identically.
  • Fixed the rich text formatting toolbar overlapping the top edge of the text area. It now sits in normal flow directly above the editor. Also “Use the Jodit editor” off only.
  • Fixed an inconsistent mouse cursor over rich text content, where a paragraph showed a text caret while the surrounding field showed a pointer.
Rules & forms
  • Fixed rules that trigger on a text or number change firing on every keystroke instead of when the field loses focus.
  • Fixed a deleted list field still being validated by a rule that referenced it, and not being removable when editing the rule.
  • Fixed the rules-tab filter hiding all rules when none matched, even with “Hide rules that do not match” unchecked.
  • Fixed the selected tab resetting to the first tab after saving, and the default selected tab shifting unexpectedly.
  • Fixed a brief flash of the “not configured” banner while a configured form was still loading.
  • Fixed the form-builder scroll position jumping to the top on certain re-renders.
vLookup
  • Fixed vLookup add/edit/delete not working when a custom event listener was attached to the section.
  • Fixed the Miscellaneous panel-size setting being ignored when opening a vLookup item in a panel. (If “Override form panel type” is set in the vLookup “Add new item” configuration, it takes precedence.)
  • Fixed assorted vLookup item-id handling errors.
Custom JS Professional & Enterprise
  • getFieldValue(fin, "LookupId") now returns a proper array of integers for multi-value lookup fields instead of a comma-separated string. If your custom JS treated this result as a string (e.g. calling .split(", ")), update it to handle an array — and note that an empty multi-select lookup now returns [] rather than "".
  • getFieldValue, setFieldValue, dffs_triggerSave and related functions now always target the correct form when a vLookup child panel is open (previously they could momentarily read values from the parent item).
  • Fixed a “Custom render function” that could cause an infinite render loop and freeze the form; results are cached after the first call — use dffs_refreshCustomRender(fin) to force a re-run.
  • Fixed a custom render function not working on a text field in the display form.
  • Fixed dffs_PreSaveAction firing on save even when required fields weren’t filled in (it now only fires when they are).
  • Fixed setFieldValue throwing an error when passed null.
  • Fixed dffs_addEventListener not passing the native DOM event to the callback.
  • Fixed dffs_hideModal throwing when called with an invalid modal id.
  • Fixed a linefeed in the “Load external JS files” field causing a load error.
  • Fixed the “Trigger from custom JS” rule condition incorrectly firing on form load.
  • Custom JS callbacks are now isolated per form. Opening an item in DispForm and then switching to EditForm no longer carries the DispForm’s dffs_ready (or any other built-in callback) over into the EditForm — each form now runs only the callbacks defined in its own Custom JS. dffs_PostUnloadAction now also runs when a form is replaced or navigated away from (not only when a panel is closed), always exactly once, and receives a calledFrom argument ("FormPanel", "FormSwitch", "FormBuilder"). Closing a vLookup child form no longer triggers the parent form’s dffs_PostUnloadAction.
Configuration, licensing & security
  • External JS files and CSS @import URLs are now fetched fresh at the start of each new browser session, so updates aren’t served from a stale cache.
  • Copying an external configuration back to the local list now enforces the external configuration’s password (previously only the local password was checked).
  • Fixed errors when loading configuration from a URL where the JSON was already parsed.
  • A fallback with manual instructions is now shown when the “Restore previous version” endpoint is unavailable on a tenant.
  • Fixed opening a form with 50+ users in a people picker triggering SharePoint 429 throttling (lookups are now batched).

Modern DFFS Admin — release history

A separate package with its own version, licensed as an Enterprise / Pro add-on. Read the guide or download it.

1.1.14 October 2026

A faster way to point the tool at another site, and a usability fix in the Bulk update tab.

Point the tool at a site by pasting its URL

Choosing another site has meant pressing Load sites and waiting while the tool fetches every site you can access. That list is thorough, and it is still there — but in a tenant with thousands of sites it can take a minute, which is a long time to wait for a site whose URL you already know.

There is now an I know my site URL link next to the button. Paste the site URL, press Check access, and the tool reads that one site to confirm you can reach it. It is a single request, so it comes back immediately however large your tenant is.

You do not have to paste a tidy URL. A link copied straight from a list view or a page works: it is trimmed back to the site it belongs to, so .../sites/marketing/Lists/Invoices/AllItems.aspx becomes .../sites/marketing, and the box shows you the site it settled on before you do anything with it.

If you cannot reach the site, the tool now says so in plain terms instead of reporting a bare “404 Not Found” — including the reminder that a missing site and a site you have no access to look identical to SharePoint, so both are worth checking.

The site must be in the same tenant as the site hosting the Admin tool; the tool cannot sign in anywhere else, and it tells you rather than failing obscurely.

Easier to type long values in Bulk update

In Search & replace, the Find and Replace with boxes shared a row, which left each of them narrow enough that a long value — a URL, say — scrolled out of sight while you typed it. They are now stacked one above the other and use the full width of the tab, so you can see what you entered. Replace field internal name got the same treatment, for consistency.

1.1.013 September 2026

Throttling protection, opt-in language selection, and a fix for built-in fields being renamed into the wrong language — all three out of one incident: a list copy on a tenant with several language packs installed hit SharePoint request throttling, and separately renamed some built-in fields into the wrong language.

Copying lists is no longer derailed by SharePoint throttling

Copying a list, or letting Promote config create a list for you, can mean hundreds of requests in quick succession — and SharePoint will start rate-limiting (“throttling”) a busy tenant that sends them. Previously this surfaced as a long list of failed fields that looked like something was wrong with the list itself.

The tool now recognises throttling for what it is and waits it out: it retries, honours the delay SharePoint asks for, and slows everything down once it sees the first sign, rather than continuing at full speed. While it is waiting, a message tells you so — a copy that has gone quiet for a minute is waiting on SharePoint, not stuck.

If the limit is still in force after all that, the run stops cleanly and tells you exactly what was left to do, so you can finish with Diff & add missing fields once things settle. It no longer tries to push on through a limit that is plainly still there.

Choose which languages to copy field names for

If your site has extra language packs installed, copying a field’s translated display names is by far the most demanding part of a copy — and it is the usual reason a copy gets throttled. It costs two extra reads per field, per language: on a 60-field list across six languages, roughly 720 requests before a single field is created.

Copy list and Promote config now show you which languages are available and let you pick the ones you want. Nothing is selected by default, so a copy brings field names across in the site’s default language only unless you ask for more. Tick the one or two languages you actually use and the copy stays fast.

Note if you use multi-language sites: this is a change from earlier versions, which always copied every installed language. If you want translated field names carried across, tick those languages before copying — there is a Select all if you want the previous behaviour.

Fixed — some built-in fields were renamed into the wrong language

When copying a list from a site with several languages installed to a site with fewer, some built-in SharePoint fields — the rating fields, for example — could end up showing their name in one of the source site’s other languages. An English list could be left with a Ukrainian field name.

This happened because the translated name was being sent to a destination that did not have that language enabled, and SharePoint applied it as the field’s ordinary name instead of as a translation. The tool now only writes translations for languages the destination site actually has, and tells you when it has skipped any.

If you copied a list before this fix and see a field name in the wrong language, correct it on the destination list — re-running the copy will not fix an existing field.

1.0.120 August 2026

A single new capability: the Bulk update tab can now reach inside a configuration and set properties on the individual form elements, not just on the configuration as a whole.

New — Element property bulk update

Bulk update previously worked on a configuration from the outside: change a Misc setting, find-and-replace text, rename a field. The new Element property mode works on the tree of elements a configuration is made of — the grid, row, col, field, pivot and html nodes that make up FormJSON, and the rules in RulesJSON. You pick elements by condition, then say which properties to write on them.

Things it can do in one pass, across every configuration you select:

  • On every field, set labelPosition to top — but only where it is currently empty
  • On the first grid, set width and widthUnit
  • On every column whose sm / md / lg / xl sizes disagree, align all four
  • On every column that has a pivot nested anywhere inside it, set the responsive sizes
  • On the field with a given internal name, set style

Each of those is a button on the tab that fills the form in for you, so you can adapt a working example rather than build one from scratch.

Conditions

A condition is a property name, a test, and a value; several conditions all have to hold. They come in three groups:

  • On this element — is, is not, contains, matches regex, is empty, is not empty, exists, does not exist
  • Across several properties — for a list like size.sm, size.md, size.lg, size.xl: all equal / not all equal
  • Elsewhere in the tree — is on a nested element / is on no nested element, and is on an enclosing element / is on no enclosing element

The structural pair selects by where an element sits rather than by what it contains: type is on a nested element pivot picks every column holding a pivot at any depth, so one nested under further rows and columns still counts, and an element never counts as nested inside itself. The enclosing pair works the other way — every field inside a pivot, or every field outside one.

Property names are dot-paths relative to the element (style, size.sm, textIsDropdown.enabled).

What to change, and what to write

What to change: every matching element, or just the first, the last, or the nth — counted per column of each configuration, in the order the elements appear.

What to write: one or more properties, each set to a value or deleted. Missing levels of a dot-path are created. List several properties comma-separated to give them all the same value. Choose Only when empty to fill a blank without touching anything already set.

Values keep their type. A value is parsed as JSON when valid, so 12 is written as a number and true as a boolean — quote it ("12") to force text, which several DFFS properties expect (width, multistepFixedHeight). The preview shows every value the way it will actually be written, so a quoted number is visibly text.

Writes that would change nothing are dropped, which is why “align all four sizes” reports only the columns that really differed.

Preview

Element property changes use the same preview as Search & replace and Replace a field: each changed column is listed with a count, and expanding it shows every individual change before anything is written. Element changes name the element as well as its path, so a row reads

[0] › children[0] › children[1] «field · BoolDefaultNo» › labelPosition

rather than a bare JSON path that tells you nothing about what you are editing.

Notes

  • Element property applies only to the JSON columns (FormJSON / RulesJSON / Misc). It edits a parsed tree, so CustomJS and CustomCSS have no elements to target and are not offered.
  • A configuration whose JSON column will not parse is reported as an error for that column and skipped, rather than failing the run.
  • Conditions are tested against every object in the column, so keep a type is … condition in place to scope them to real form elements — at least one condition is required. Put it first as well: conditions are checked in order and stop at the first failure, so a cheap type is col keeps the structural tests from scanning the whole configuration.
  • DFFS writes property values lowercase (labelPosition is left / top), and internal names are case-sensitive with spaces encoded as _x0020_ — match the casing that is stored.

1.0.08 August 2026

Initial release. Browse configs, Activate DFFS, Promote config, Bulk update (Misc setting, Search & replace, Replace a field), Copy list, Remote import, and Email flow.