Custom CSS & custom HTML
Professional & EnterpriseEvery DFFS form has a Custom CSS tab, and the form layout can hold HTML sections — arbitrary markup placed alongside your fields. Between them you can restyle anything the configuration options don’t reach.
This is the hand-written route. If you’d rather not write CSS, the Theme Builder generates it for you from a visual editor — though it’s an Enterprise feature or a Professional add-on, whereas Custom CSS is included with every Professional and Enterprise license.
1. Follow the site theme instead of hardcoding colors
The single most useful thing to know here: the colors from the site’s current SharePoint theme are published as CSS variables. Reference them and your form tracks the site’s branding — including a live Change the look switch — instead of drifting out of step the first time someone re-themes the site.
<div style="color:var(--themePrimary)">Themed heading</div>
<div style="background:rgba(var(--themePrimary-rgb), 0.1)">Subtle themed tint</div>
- The full palette is available —
themePrimary,themeDark,neutralLight,bodyText,bodyBackground,link, and the rest of the SharePoint theme slots. - Each color also has an
-rgbvariant for transparent tints insidergba(...)—var(--themePrimary-rgb). - Every token has a
--dffs-prefixed alias (var(--dffs-themePrimary)) in case another solution on the page already defines the plain name.
See what’s available on a site: open the browser console on a page with a DFFS form and type
dffs_themeVarsto list every color token and its resolved value.These variables only fill in where SharePoint hasn’t already themed an element — they never override SharePoint’s own theming.
2. The classes you can target
DFFS renders fields with stable class names, so you can style by structure rather than guessing at generated markup:
| Class | What it marks |
|---|---|
.dffs-field | The wrapper around a single field — label and control together. |
.dffs-field-label | The field’s label element. |
.dffs-required | Applied to a field that is currently required. |
.dffs-readonly | Applied to a field that is currently read-only — whether a rule made it so, or it is on a display form. |
The Custom CSS tab documents the full set in-product; these cover most styling.
Buttons
Every button DFFS renders carries .dffs-btn — the class the Theme Builder writes its button rules against — plus a second class naming the individual button. Target the second one to style a single button without touching the rest.
| Class | The button it marks |
|---|---|
.dffs-btn-vlookup | A vLookup’s Add new item button. |
.dffs-btn-repeating-section | A repeating section’s Add row button. |
.dffs-btn-related-items | The related items add button. |
.dffs-btn-save | The form’s Save button. |
.dffs-btn-cancel | The form’s Cancel button — and the Cancel button in a dffs_showModal or dffs_showDialog message. |
.dffs-btn-primary | The OK button in a dffs_showModal or dffs_showDialog message. |
.dffs-btn-print-pdf | The Save as PDF button. |
All three add buttons carry
.dffs-btn. Before 2.1 only the vLookup one did, so a themed form showed one styled button and two stock ones. If you had styled around that, the repeating section and related items buttons now follow your theme as well.
A custom form class scopes everything. Set one in the Misc settings (for example
contoso-theme) and write your rules under.contoso-theme. That keeps your CSS from leaking into other DFFS forms on the same page, which matters on a page hosting more than one form.
Panels from dffs_showPanel
A panel opened with dffs_showPanel carries three classes: .dffs-modal, like any DFFS dialog, plus .dffs-panel and one of .dffs-panel-right, .dffs-panel-left, .dffs-panel-top or .dffs-panel-bottom. Target the second to style every panel, the third to style one edge, or the modalId you passed to style a single panel.
A panel’s thickness — its width on the left and right, its height on the top and bottom — is the --dffs-panel-size CSS variable, so it can be retuned without !important:
.dffs-panel-right { --dffs-panel-size: 600px; }The panel rules are written to win over Fluent UI’s own sizing but not over yours: a rule on .dffs-modal.dffs-panel or more specific in Custom CSS takes effect.
Stacking order
Worth knowing if you position something over the form: DFFS form content paints at 999997–999998 (labels, tooltips and sticky tab rows). In a side panel — a vLookup child form, or the configuration screen — the panel’s command bar and its Save/Cancel footer sit above that at 999999, a full-screen code editor at 1000000, and the dim overlay shown while saving at 1000001. Custom CSS that needs to clear the panel header has to beat 999999.
3. Custom CSS and printed output
Your Custom CSS applies to Print to PDF output as well. The print markup carries the same .dffs-field and .dffs-field-label classes rather than inline styles, so rules you already wrote take effect in the PDF without needing !important.
One exception:
.dffs-requiredis not applied in the print layout — required-field state isn’t meaningful in a finished document — so don’t build print styling on it.
4. Where custom CSS can come from
| Source | Scope | Order |
|---|---|---|
| The form’s own Custom CSS tab | That form | Applied first |
| Reusable Content CSS snippet Enterprise | Any form that references it | Appended to the form’s own CSS |
GlobalCustomCSS on the central site Enterprise | Every form in the tenant | Applied after per-form CSS, so it takes precedence |
The last row is worth remembering when debugging: if a form ignores a rule you just wrote, check whether a tenant-wide GlobalCustomCSS is overriding it. See the central site setup guide.
CSS referenced by URL — in a Reusable Content item or a central setting — must point at a file in a
DFFS_Assetslibrary. External and third-party URLs are deliberately rejected; host the file inDFFS_Assetsand reference it from there.
Portable asset paths
A stylesheet that references a file by absolute path — /sites/Demo/SiteAssets/x.css — has to be edited by hand every time the configuration is copied to another site or promoted through DEV/UAT/PRD. Two tokens avoid that:
| Token | Resolves to | Classic DFFS |
|---|---|---|
{currentSite} | The site collection the form is in | ~sitecollection |
{currentWeb} | The site (web) the form is in | ~site |
{assetUrl} | The asset base URL configured for this environment — a CDN, an Azure blob container, or any folder outside SharePoint | — |
@import "{currentSite}/SiteAssets/styles.css";
.dffs-field-logo {
background-image: url("{currentWeb}/SiteAssets/logo.png");
}They resolve anywhere in the stylesheet, not only inside @import — so an image referenced with url() travels with the configuration too. The same tokens work in Global Custom CSS, the Default Theme, and in the Custom JS tab’s Load external JS files list. Matching is case-insensitive, and the classic spellings are accepted so a path carried over from classic DFFS works unchanged.
{assetUrl} is set per environment. On each stage’s row under Environment settings — the same DEV/SIT/UAT/PRD mapping the promotion banner uses — give the stage an asset base URL. One configuration then loads each environment’s own assets with no path edited on promotion. A site that is in no mapping at all falls back to the PRD asset URL, so a configuration copied to a sandbox or a customer site keeps working; if no asset URL is configured anywhere the token is left in place unresolved, so the error message names it rather than reporting a 404 from a path that pointed nowhere.
External JS files need CORS; stylesheets and images do not. An external JS file is fetched by the form rather than added as a script tag, so a script on another domain only loads if that server allows cross-origin requests from your SharePoint domain.
@importandurl()in Custom CSS are ordinary browser loads and need nothing. A script blocked this way says so, rather than reporting the same generic failure a missing file does.
Do not put a SAS token in an asset URL if you can avoid it. It is stored in the form configuration and is visible to anyone who can open the configuration. A container with public read access is the safer setup.
Custom JS code is deliberately left alone — only the external file list is resolved. Rewriting tokens inside arbitrary JavaScript would be a surprising thing to do to your source. And in a vLookup child form whose list lives in a different site collection,
{currentSite}resolves to the parent’s site collection; use{currentWeb}there.
5. Custom HTML sections
An HTML section is a form element holding markup you write. Use it for headings, instructions, callouts, legal text, or a small themed panel between fields.
- Use the theme variables above rather than hardcoded hex — it’s the difference between a panel that follows the site and one that looks wrong after a re-theme.
- Dynamic content works inside HTML sections — field values and variables can be embedded with tokens. See Dynamic content & tokens.
- Inline
<script>is not supported in a Reusable Content form element. If the markup needs JavaScript, put it in the Custom JS tab, or in a Reusable ContentCustomJSitem linked as a dependency. - To share one block across many forms, promote it to Reusable Content — edit the source once and every form that references it updates.