Module Settings Schema v5.0
XMod Pro's Custom Module Settings are per-instance values referenced from your view or form via [[Module:settingName]] tokens — handy for letting an admin adjust things like page size, headings, or feature toggles without editing the file itself.
In v4, those settings were untyped name/value pairs that the admin had to know about and enter manually. In v5 you can declare them with a #settings directive at the top of your view or form. The Configure page reads that declaration and presents one row per setting — with a label, optional help text, a toggle, and an input control matched to the data type.
Where the directive goes
Place the directive once near the top of the view or form file, inside an XMP comment block. In the editor, use the user-code comment syntax [-- #settings ... --]. When the file is written to disk as ASCX, the same content is wrapped in an ASP.NET comment <%-- #settings ... --%>. Both formats are recognized.
The directive content is a JSON object with two top-level keys: an optional description and a required settings array.
[-- #settings
{
"description": "Settings for the Article List view",
"settings": [
{ "Name": "PageSize", "DefaultValue": 10, "Max": 100 },
{ "Name": "Layout", "Items": ["list", "card", "table"] },
{ "Name": "Heading", "HelpText": "Optional heading shown above the list" },
{ "Name": "ShowAddButton", "DefaultValue": true }
]
}
--]If a file has more than one #settings block, only the first is used and a warning is recorded.
Setting Properties
| Property | Required | Default | Description |
|---|---|---|---|
| Name * | string | The setting's identifier. Used in [[Module:Name]] tokens and as the UDS_Name storage key. Word characters only (A-Z, a-z, 0-9, _). | |
| Label | string | inferred from Name | Human-readable label shown in the Configure UI. |
| DataType | string | inferred | One of text, integer, boolean, choice. |
| DefaultValue | matches DataType | none | Informational default shown when the toggle is off; pre-populates the input the first time it's toggled on. |
| HelpText | string | none | Description shown below the input control. |
| Required | boolean | false | When true, the toggle is forced on and a value must be supplied before saving. |
| Min / Max | integer | none | Range constraints for integer settings. |
| Items | array | none | Options for choice settings. String array (value = label) or {Text, Value} objects. |
| Group | string | none | Reserved for future use — settings sections. Not rendered in v5.0. |
| Access | string | "host" | Reserved for future use — Admin-vs-Host visibility. Not honored in v5.0; all settings still require Host access. |
* Required property
Property Details
Convention over configuration
{ "Name": "Heading" } is a complete, valid setting. Everything else is inferred from Name and any other properties you supply, using rules designed to do the right thing without explicit configuration.
Name: The setting's identifier. It's the key used by
[[Module:Name]]tokens at runtime, and it's the suffix on theUDS_Namestorage key in DNN's ModuleSettings table. Only word characters are allowed (letters, digits, underscores) — no spaces, hyphens, or punctuation. DuplicateNamevalues across settings are a parse error.Label: The text shown in the Configure UI for this setting. When omitted, XMod Pro generates one by splitting
Nameat PascalCase boundaries. Acronyms are kept intact:Name Generated Label PageSizePage Size ShowAddButtonShow Add Button HTMLOutputHTML Output IDID showURLFieldShow URL Field Set
Labelexplicitly when the auto-generated form doesn't read well or when you want a different display name (for example, "Items per page" instead of "Page Size").DataType: One of
text,integer,boolean, orchoice. When omitted, XMod Pro infers the type from the other properties using these rules, in order:Itemsis present →choiceDefaultValueistrueorfalse→booleanDefaultValueis a number, orMin/Maxis set →integer- Otherwise →
text
Setting
DataTypeexplicitly overrides inference. The most common reason to do that: you want atextinput even though you've supplied anItemsarray (which would otherwise inferchoice).Each data type maps to a specific input control in the Configure UI:
DataType Input control textText input integerNumber input. Min/Maxare applied as both HTML attributes and JS validation.booleanCheckbox. choiceSelect dropdown populated from Items. If the setting is notRequired, the dropdown also includes a "(Use Default)" option that means no value saved.DefaultValue: A suggested value, not a fallback that gets stored automatically. It serves three purposes:
- Shown as informational text on the row when the toggle is off ("Default: 10")
- Pre-fills the input the first time the toggle is flipped on
- For
choice, must match one of theItemsvalues (validated at parse time)
The literal type matters — use a JSON number for
integersettings and a JSON boolean (true/false) forbooleansettings. Decimal numbers are not supported in v5.0; useDataType: "text"if you need to store a decimal.Omitting
DefaultValuemeans the[[Module:Name]]token resolves to an empty string when no value has been saved — the same behavior as v4.x for unset settings.HelpText: A short description rendered below the input control. Useful for explaining what the setting does, what units to use, or what valid values look like. Plain text — no markdown.
Required: When
true, the row's toggle is forced on and can't be turned off. If the user clears the value before saving, the save is blocked with an inline validation message. Use this for settings the view or form genuinely won't work without (an API key, a folder path, etc.).Min / Max: Range constraints for
integersettings. Both are optional and can be set independently. They're enforced two ways: as HTMLmin/maxattributes on the number input (browser-side spin buttons), and as JavaScript validation on save (catches users who type an out-of-range value directly). Setting either property when noDataTypeis given is enough to inferinteger.Items: The options for a
choicesetting. Two formats are accepted, and you can mix them in the same array:String array — when the displayed text and the stored value are identical:
json"Items": ["list", "card", "table"]{Text, Value}objects — when the displayed text should differ from the stored value:json"Items": [ { "Text": "Card Grid", "Value": "card" }, { "Text": "Data Table", "Value": "table" }, { "Text": "Plain List", "Value": "list" } ]The dropdown shows
Text; the saved value isValue. If you set aDefaultValueon achoicesetting, it must match one of theValuestrings (string array entries count as both Text and Value).Group reserved: Reserved for a future feature where settings can be organized into named sections in the Configure UI. The property is parsed and preserved on the server side, but it's not rendered in v5.0 — every setting appears in a single flat list.
Access reserved: Reserved for a future feature where some settings can be made visible to Administrators (in addition to Hosts). The property is parsed and preserved, but in v5.0 all custom settings still require Host access regardless of this value.
Examples
Minimal — one setting, no inference
{ "settings": [ { "Name": "Heading" } ] }Heading becomes a text setting with the label "Heading", no help text, no default, and a plain text input in the Configure UI.
Range-bounded number with help text
{
"settings": [
{
"Name": "PageSize",
"DefaultValue": 10,
"Min": 1,
"Max": 100,
"HelpText": "How many records to show per page (1–100)."
}
]
}integer is inferred from DefaultValue being numeric. The label is auto-generated as "Page Size". The input is an HTML number control bounded to 1–100.
Choice with friendly labels
{
"settings": [
{
"Name": "Layout",
"DefaultValue": "card",
"Items": [
{ "Text": "Plain List", "Value": "list" },
{ "Text": "Card Grid", "Value": "card" },
{ "Text": "Data Table", "Value": "table" }
]
}
]
}choice is inferred from Items. The dropdown shows the friendly text but stores the short value, which is what [[Module:Layout]] returns at runtime.
Required text with explicit label
{
"settings": [
{
"Name": "GoogleApiKey",
"Label": "Google Maps API Key",
"Required": true,
"HelpText": "Get one at console.cloud.google.com."
}
]
}The toggle is forced on. The save is blocked until a value is entered.
Merge Behavior
When a module instance has both a view and a form assigned, the Configure page reads the #settings block from each file and merges them by Name into a single list. If both files declare a setting with the same Name, the view's definition wins and a warning is shown to the admin ("Setting 'X' is defined in both the template and form. Using the template definition.").
When the assigned view or form changes, the page re-reads the schema and updates the list. Saved values for settings that no longer appear in the new schema move to the Other Settings section, where they can be kept or removed individually.
Validation Errors
Schema errors are reported on the Configure page above the settings list, but they don't block parsing — whatever could be parsed is still shown. This way a single typo doesn't hide all the settings.
Common errors:
| Error | Cause |
|---|---|
| Setting at index N has no Name or Name is empty | Missing or blank Name property |
| Setting 'X' has invalid characters in Name | Name contains characters other than letters, digits, underscores |
| Duplicate setting name: 'X' | Two entries share the same Name |
| Setting 'X' Items array is empty | Items was supplied but contained no entries |
| Setting 'X' DefaultValue (...) does not match any Items value | DefaultValue for a choice setting doesn't match any of the values |
| Setting 'X' has decimal DefaultValue (3.5) | Decimals are not supported for integer settings — use DataType: "text" instead |
| Setting 'X' DefaultValue (200) exceeds Max (100) | DefaultValue is outside the declared range |
| Multiple #settings blocks found. Only the first block is used | More than one directive in the file (warning, not error) |
Backward Compatibility
The [-- ... --] comment syntax is silently ignored by XMod Pro v4.x. A view or form with a [-- #settings --] block runs unchanged on older XMP installations — the directive is invisible there. The schema-driven UI is the only thing that's new in v5.0; the underlying UDS_* storage and the [[Module:settingName]] token continue to work exactly as before.