# Admin UI Migration Guide (major release)

> Who this is for: developers with customization work on the CBX admin UI — custom CSS, custom admin JS, or overridden backend view/property templates. The upc…

Source: CBX documentation, version 3.x (released). Canonical page: https://docs.configbox.at/docs/customization/admin_ui_migration. Last updated 2026-08-01.

---
**Who this is for:** developers with customization work on the CBX **admin (backend)** UI — custom
CSS, custom admin JS, or overridden backend view/property templates. The upcoming **major release**
modernizes the admin form & list markup, CSS and JavaScript, and **deliberately introduces breaking
changes** to the admin HTML structure and CSS class names. This guide tells you exactly what changed and
how to amend your customizations.

If you only customize the **frontend** (configurator, cart, checkout, customer form), or you do not
override admin templates / target admin CSS classes, you are very likely unaffected — but skim §1 to be
sure.

Read first: `com_configbox_customization_overview.md`, and — if you override templates —
`com_configbox_overriding_views_and_templates.md`. For adding your own admin CSS/JS, see
`com_configbox_assets_and_amd.md`. All paths are relative to the component root
`docroot/components/com_configbox/`.

> This guide is **updated as each migration slice ships**. The "Status" column below tells you which
> slices are already in the code you have. A slice not yet marked *Done* has not changed anything yet.

---

## 1. What changed, in one minute

The admin UI is rendered by the **Kenedo framework** (generic list + form templates, plus per-property
field templates). The modernization does three things:

1. **Renames the structural CSS classes.** The old, inconsistent mix of prefixes
   (`kenedo-*`, `listing-*`, `configbox-*`, `backend-*`, `view-admin`) for the admin *chrome* (list
   table, detail form, toolbar, field groups) is replaced by a single, consistent **`cb-*`** prefix, and
   leans on **Bootstrap 5** component classes (`.table`, `.card`, `.btn`, `.alert`, `.pagination`,
   `.form-control`, …) wherever BS5 already provides the thing.

2. **Modernizes the HTML** to clean, semantic Bootstrap 5 markup (BS 5.3.8 is already bundled and scoped
   under `.cb-content`).

3. **Scopes all admin CSS under `.cb-content`** to stop CSS bleeding in from — and out to — the host CMS
   (Joomla/WordPress/Magento) and other extensions.

### Two conventions that DO NOT change — rely on them

- **`.trigger-*` classes are stable.** They are the documented JS event-handler hooks. If your custom JS
  binds to `.trigger-…`, or your templates emit `.trigger-…` so CBX's JS picks them up, that keeps
  working. **Never** attach styling to `.trigger-*` — style with a `cb-*`/BS5 class instead.
- **`.property-*` classes are kept.** The property-widget styling family (`property-name-<name>`,
  `property-type-<type>`, `property-label`, `property-body`, and the field-group inner names) is
  preserved, so property-level custom CSS and the `appliesWhen` visibility mechanism keep working.
- **`data-*` attributes are preserved verbatim** (`data-record`, `data-properties`,
  `data-property-definition`, `data-key`/`data-value`, `data-task`, `data-init-calls-*`, etc.).

So the breaking surface is essentially: **structural chrome classes renamed to `cb-*`, some HTML
restructured, and custom CSS that was unscoped may need re-scoping.**

---

## 2. How to amend your customizations

### If you have custom admin **CSS**
- Search your stylesheet for the old structural class names (see the map in §4) and update them to the
  new `cb-*`/BS5 equivalents.
- If your rules were **unscoped** (bare `.kenedo-…`, `.view-admin …`), scope them under `.cb-content` to
  match the new baseline and win specificity battles against host-CMS CSS
  (e.g. `.cb-content .cb-list { … }`). Your `custom.css` still loads **last** (after `admin.css`), so you
  keep the final say.
- Rules that target `.property-*` or `.trigger-*` generally need **no change**.

### If you have custom admin **JavaScript**
- If you select elements by the old structural classes (`.kenedo-listing-form`, `.item-row`,
  `.kenedo-details-form`, …), update the selectors per §4.
- If you bind to `.trigger-*` hooks or read `data-*` attributes, **no change** needed.

### If you **override** admin view or property templates
- Overrides that emit the **generic** markup (list/form/field-group) must be re-synced to the new markup.
  The cleanest path for most overrides is to **re-base** them on the new stock template and re-apply your
  changes — see `com_configbox_overriding_views_and_templates.md` for the lookup order and technique.
- Property-template overrides (`…/properties/tmpl/<type>.php`) keep the `.property-*` contract; update
  only the inner control markup to BS5 where you had copied stock structure.

---

## 3. Migration slices — status & changelog

| Slice | Area | Status |
|---|---|---|
| 1 | Generic **list** view (table, toolbar, filters, pagination, messages) | **In this build** |
| 2 | Generic **form** view + field groups | **In this build** |
| 3 | Property **field** templates (+ per-type JS/CSS extraction) | **In this build** |
| 4 | Custom backend view templates (incl. rule/calc engine editors) | **In this build** |
| 5 | Dependency swaps (modal, datepicker, select) — **admin only** | **In this build** |
| 6 | CSS/JS consolidation & anti-bleed sweep | **In this build** |

_Each slice's concrete renames/removals are appended below as it ships._

<!-- SLICE-CHANGELOG-START -->

### Slice 1 — Generic list view

The backend **list** (data grid) markup, CSS and JS moved to `cb-*` / Bootstrap 5. The table now
uses Bootstrap's `.table`, pagination uses `.pagination`, and messages use `.alert`. All list CSS is
scoped under `.cb-content`.

**Renamed (structural — update custom CSS/JS selectors and list template overrides):**

| Old | New |
|---|---|
| `.kenedo-listing-form` | `.cb-list` |
| `.kenedo-listing` (table) | `.cb-list-table` (+ `.table`) |
| `.sortable-listing` / `.unsortable-listing` | `.cb-list--sortable` / `.cb-list--static` |
| `.item-row` | `.cb-list-row` |
| `.field-<prop>` (cells) | `.cb-cell-<prop>` |
| `.kenedo-title-and-tasks` | `.cb-toolbar` |
| `.kenedo-page-title` | `.cb-title` |
| `.kenedo-after-title` | `.cb-after-title` |
| `.kenedo-filters` / `.kenedo-filter` | `.cb-filters` / `.cb-filter` |
| `.listing-filter` | `.cb-list-filter` |
| `.kenedo-search` (filter button) | `.cb-list-filter-btn` |
| `.listing-link` | `.cb-list-link` |
| `.listing-data` | `.cb-list-data` |
| `.kenedo-item-checkbox` | `.cb-item-checkbox` |
| `.kenedo-check-all-items` | `.cb-check-all` |
| `.sort-handle` | `.cb-sort-handle` |
| `.kenedo-tasks` / `.kenedo-task-list` | `.cb-tasks` / `.cb-task-list` |
| `.kenedo-pagination` | `.cb-pagination` |
| `.kenedo-limit` / `.kenedo-limit-select` | `.cb-pagination-limit` / `.cb-pagination-limit-select` (+ `.form-select`) |
| `.kenedo-pagination-list` | `.cb-pagination-pages` (+ Bootstrap `.pagination` / `.page-item` / `.page-link`) |
| `.kenedo-hidden-fields` | `.cb-hidden-fields` |
| `.kenedo-messages` / `.kenedo-messages-error` / `.kenedo-messages-notice` | `.cb-messages` / `.cb-messages-error` / `.cb-messages-notice` (+ `.alert` `.alert-danger` / `.alert-success`) |
| task button `.btn-default` | `.btn-outline-secondary` |

> **Messages** are shared list+form infrastructure driven by one JS function, so the `.kenedo-messages*`
> → `.cb-messages*` rename was applied to **all** views that render a message block in this build
> (not just lists).

**Unchanged (rely on these):** `.trigger-*` JS hooks (incl. `.trigger-kenedo-list-task`,
`.trigger-order-list`, `.trigger-change-page`, `.trigger-toggle-record-activation`), and the detail
**form** wrapper `.kenedo-details-form` (migrates in Slice 2). All `data-*` attributes.

### Slice 2 — Generic form view + field groups

The backend **detail form**, the **field groups** (collapsible fieldsets), the **property wrapper**, and the
"item is in use" **usage block** moved to `cb-*`. The property *widget* identity classes are **kept** (see
below), so `appliesWhen` visibility and per-property custom CSS keep working.

**Renamed (structural — update custom CSS/JS selectors and form/group template overrides):**

| Old | New |
|---|---|
| `.kenedo-details-form` (form wrapper / JS hook) | `.cb-form` |
| `.kenedo-properties` (fields container) | `.cb-fields` |
| `.kenedo-property` (single field wrapper) | `.cb-field` |
| BS4 `.form-group` (was on every field wrapper) | _removed_ (use `.cb-field`) |
| `.property-group` | `.cb-field-group` |
| `.property-group-<name>` | `.cb-field-group-<name>` |
| `.property-group-legend` | `.cb-field-group-legend` |
| `.property-group-content` | `.cb-field-group-content` |
| `.property-group-properties` | `.cb-field-group-body` |
| `.property-group-notes` / `.property-group-notes-title` | `.cb-field-group-notes` / `.cb-field-group-notes-title` |
| `.property-group-opened` / `.property-group-closed` | `.cb-field-group--open` / `.cb-field-group--closed` |
| `.property-group-using-toggles` | `.cb-field-group--toggles` |
| `.property-group-toggle-state` (hidden state input) | `.cb-field-group-state` |
| `.kenedo-item-usage` | `.cb-item-usage` |
| `.kenedo-usage-message` | `.cb-usage-message` |
| `.kenedo-candelete-usage-entry-name` | `.cb-usage-entry-name` |
| `.kenedo-candelete-usage-entry-link` | `.cb-usage-entry-link` |
| `.kenedo-candelete-message` / `.kenedo-candelete-usage-entries` | `.cb-candelete-message` / `.cb-usage-entries` |
| `.kenedo-hidden-fields` | `.cb-hidden-fields` |

**Kept — do NOT change (the property-widget identity family):**

- `.property-name-<name>`, `.property-type-<type>` — still on every `.cb-field` wrapper **and** on each
  `.cb-field-group`. The wrapper **`id` is still `property-name-<name>`** (the field-group toggle and the
  `appliesWhen` visibility engine both read it).
- `.property-label`, `.property-body`, `.invisible-field`, `.required`, `.required-flag`.
- `.trigger-kenedo-form-task` (the form task-button hook), `.kenedo-new-tab` (open-in-new-tab hook),
  `.kenedo-datepicker` (migrates in Slice 5), all `data-*` attributes.

> The `.property-*` widget internals (`.property-type-string` / `-dropdown` / `-file` / `-image` /
> `-translatable` / `-multiselect` / `-published` / `-boolean` / … control markup) are **not** touched in
> this slice — they migrate in **Slice 3 (property field templates)**. If you override a property template,
> only the outer wrapper class changed (`.cb-field`); the inner control structure is unchanged for now.

> **Scope note:** the 14 bundled payment-provider settings forms (`psp_connectors/*/settings.php`) and the
> custom backend views that hand-roll a form shell (admincalculation, admincustomer, adminuserfields,
> adminnotification, adminoptionassignment, adminorder, admincalccode, admincalcmatrix) were re-synced to
> `.cb-form` / `.cb-fields` / `.cb-field` in this build as well, so nothing is left in a half-migrated state.

### Slice 3 — Property field templates + per-type JS/CSS extraction

Two changes ship together:

**(a) Per-type JS/CSS is now co-located with the property type**, not in the monolithic `admin.js`/`admin.css`.
Each property type declares its own assets via the existing hooks on its `KenedoProperty` subclass:
`getStyleSheetUrls()` (→ `assets/css/properties/<type>.css`), `getJsInitCallsOnce()` / `getJsInitCallsEach()`
(→ `assets/javascript/properties/<type>.js`, an AMD module). The Kenedo view collects these and injects them on
page load **and** on XHR view injection. This is the same mechanism `rule` / `calculation` / `groupPrice` already
used. New stock modules: `translatable`, `datetime`, `dropdown`, `file` (shared by `image`), `multiselect`.
New stock stylesheets: `translatable`, `dropdown`, `file`, `image`, `multiselect`, `boolean` (shared by
`published`), `childentries`, `taxclassrates`, `shapedivermodel`, `shapedivergeometry`, `shapediverparameter`.

**What this means for you:** if your custom admin JS/CSS targeted the *removed* code paths inside `admin.js`
(`initHtmlEditors`, `initDatePickers`, the `.property-type-dropdown` branch of `initChosenDropdowns`) or the
per-type rules that used to live in `admin.css`, those moved. To add behaviour/styling to a specific property
type, prefer the same pattern: override the property class's `getStyleSheetUrls()` / `getJsInitCalls*()`. Your
`custom.css` / `custom.js` still load last and keep the final say.

**(b) Property-template inner classes renamed to `cb-<type>-*`** (the `.property-type-*` / `.property-label` /
`.property-body` / `.trigger-*` contracts are unchanged):

| Type | Old inner class | New |
|---|---|---|
| translatable | `translations` / `translation` / `translation-label` | `cb-translations` / `cb-translation` / `cb-translation-label` |
| translatable | `language-switchers` / `language-switcher` | `cb-lang-switchers` / `cb-lang-switcher` |
| translatable | `kenedo-translatable-textarea` / `translations.text-area` | `cb-translatable-textarea` / `cb-translations--textarea` |
| translatable | `using-editors` (wrapper modifier) | `cb-using-editors` |
| file / image | `file-wrapper` / `file-current-file` / `file-uploader` | `cb-file-wrapper` / `cb-file-current` / `cb-file-uploader` |
| file / image | `file-delete(-checkbox/-label)` / `file-upload(-field)` / `file-link` | `cb-file-delete*` / `cb-file-upload*` / `cb-file-link` |
| file / image | `highlighted` / `no-file-text` / `valid-extensions` | `cb-file-missing` / `cb-file-none` / `cb-file-valid-extensions` |
| file / image | `show-file-uploader` / `file-upload-cancel` (JS hooks) | **`trigger-show-file-uploader`** / **`trigger-file-upload-cancel`** |
| multiselect | `multiselect-toggles` / `extended-multiselect` | `cb-multiselect-toggles` / `cb-multiselect-extended` |
| multiselect | `checkbox-field` / `checkbox-item` / `checkbox-label` (from `KenedoHtml::getCheckboxField`) | `cb-checkbox-field` / `cb-checkbox-item` / `cb-checkbox-label` |
| shapedivergeometry / parameter | `sd-note-bad-geometry` / `sd-note-bad-parameter` | `cb-sd-note-bad-geometry` / `cb-sd-note-bad-parameter` |
| shapediver* | `parameter-selection-help(-heading)` | `cb-sd-parameter-selection-help(-heading)` |

**Kept (rely on these):** `.kenedo-html-editor` (platform-level TinyMCE hook), `.kenedo-datepicker` (jQuery-UI
mount — the widget swap is Slice 5), `.radio-button-label` (shared with the frontend via
`KenedoHtml::getRadioButtonField`), and all `.trigger-*` / `.property-*` / `data-*`.

> **Not extracted this slice** (kept in `admin.css`, already view-scoped so no bleed): `paymentmethodparams`
> (its inner control classes are emitted by encoded code) and `usergroupdiscount` (no plaintext property class
> to hook). These render unchanged.

### Slice 4 — Custom backend view templates

The admin views that hand-roll their own markup (instead of using the generic list/form) had their bespoke
structural classes renamed to view-scoped `cb-*` prefixes, together with their paired CSS and JS. Each view
family uses its own prefix; the `.trigger-*` hooks, `data-*` attributes, vendored library classes, and shared
generic classes (`.key`, `.value`, `.active`, `.opened`, `.flash`, BS grid) are unchanged.

| View(s) | Prefix | Examples |
|---|---|---|
| adminorder (order detail) | `cb-order-*` | `order-meta-info`→`cb-order-meta`, `order-overview`→`cb-order-overview`, `user-info-table`→`cb-order-info`, `admin-order-address`→`cb-order-address` |
| admindashboard | `cb-dash-*` | `box`→`cb-dash-box`, `issue-item`→`cb-dash-issue`, `toggle-handle`→`cb-dash-toggle-handle`, `software-update`→`cb-dash-update`, `stat-*`→`cb-dash-stat-*` |
| adminproducttree | `cb-tree-*` | `product-list`→`cb-tree-product-list`, `product-item`→`cb-tree-product`, `sub-list`→`cb-tree-sublist`, `sub-list-trigger`→`cb-tree-trigger`, `list-opened`→`cb-tree-open` |
| adminmainmenu | `cb-menu-*` | `menu-list`→`cb-menu-list`, `menu-list-item`→`cb-menu-item`, `menu-link`→`cb-menu-link`, `sub-items`→`cb-menu-subitems` |
| adminuserfields | `cb-userfields-*` | `user-fields-table`→`cb-userfields-table`, `userfield-<name>`→`cb-userfield-<name>`, `show-*`/`require-*`→`cb-userfields-show-*`/`-require-*` |
| adminoptionassignment | `cb-optassign-*` | `option-data`→`cb-optassign-option`, `option-fields-target`→`cb-optassign-fields-target`, `xref-data`→`cb-optassign-xref` |
| admincalculation / admincalccode | `cb-calc-*`, `cb-calccode-*` | `calc-type-subview`→`cb-calc-subview`, `name-type`→`cb-calc-name-type`, `calculation-code-notes`→`cb-calccode-notes` |
| **Rule editor** (adminruleeditor*, condition classes, engine) | `cb-editor-*` (shared chrome), `cb-rule-*` | `picker-tabs`→`cb-editor-picker-tabs`, `drop-area`→`cb-editor-drop-area`, `operator-picker`→`cb-editor-operator-picker`, `rule-area`→`cb-rule-area`, `button-store`→`cb-rule-btn-store` |
| **Calc formula editor** (admincalcformula*, calc-term classes, engine) | `cb-editor-*` (shared chrome), `cb-calc-*` | picker chrome shared with the rule editor; `button-limit-term-width`→`cb-calc-btn-limit-width`, term/parameter internals → `cb-calc-*` |
| **Calc matrix** (admincalcmatrix) | `cb-matrix-*` | `calc-matrix`→`cb-matrix-table`, `matrix-wrapper-table`→`cb-matrix-wrapper`, `column-parameter`→`cb-matrix-column`, `input-value`→`cb-matrix-input`, `axis-parameter-picker`→`cb-matrix-axis-picker` |

Also: the shared button utility `.backend-button-small` → **`.cb-btn-small`**; `.kenedo-page-title` (in the
few custom views still using it) → **`.cb-title`**.

> **Kept — do NOT change:** the vendored **dragtable** classes on the calc matrix
> (`.dragtable-drag-handle`, `.dragtable-drag-boundary`, `.dragtable-col-placeholder`, …) are third-party
> library API and are unchanged. All `.trigger-*` hooks (`.trigger-add-row`, `.trigger-add-column`,
> `.trigger-remove`, `.trigger-edit-rule`, `.trigger-toggle-sub-items`, …), `.kenedo-popup*`,
> `.kenedo-new-tab`, and the shared `.item`/`.bracket`/`.operator`/`.parameter`/`.input`/`.selected` calc-item
> primitives are unchanged.

> **Engine-editor note (releases):** the rule and calc editors' condition/term HTML is produced partly by the
> **ionCube-encoded** rules/calc engine (`helpers/encoded/{13,14,15}/rules.php`, `calculation.php`). This
> build renamed the classes in the plaintext engine sources too, so on a machine that runs the plaintext
> engine (dev), the editors work immediately. **To ship, the engine must be recompiled** from the updated
> plaintext sources — the class names in the encoded artifacts must match the new CSS/JS.

> **Out of scope:** `adminorderslip` and the other PDF documents (quotation/invoice) are print artifacts with
> their own isolated stylesheets (`pdf-orderslip.css` etc.), not admin chrome — left unchanged.

### Slice 5 — Dependency swaps (admin only)

Three ageing widget libraries were replaced in the **admin** UI. The **frontend** (configurator, cart,
checkout, customer form, calendar question) intentionally keeps the old libraries — this slice is scoped to
the admin, like Slices 1-4.

**1. jQuery Colorbox → Bootstrap 5 modal.** The `.trigger-open-modal` handler (`kenedo.js
onOpenColorBoxModal`) now opens the target `href` in a Bootstrap 5 iframe modal (`.cb-iframe-modal`) instead
of Colorbox. The `.trigger-open-modal` hook and its `data-modal-width` / `data-modal-height` attributes are
unchanged. The `cbj.colorbox` AMD path and the Colorbox CSS block were removed.

**2. jQuery-UI datepicker → native `<input type="date">`.** The **datetime** property
(`properties/tmpl/datetime.php`) now renders a native date input (no `.kenedo-datepicker` mount, no calendar
icon); the `configbox/properties/datetime` JS module was removed (native inputs need no JS). The **adminorders**
date filters (`filter_startdate` / `filter_enddate`) are native date inputs too, and `admin.js`
`initListFilterDatePickers` was removed. If you override `datetime.php`, note it is now a plain
`input[type="date"]` (value normalised to `YYYY-MM-DD`). The frontend calendar question type keeps jQuery-UI.
`.datepicker` class → `.cb-date-input`.

**3. Chosen → Tom Select (Bootstrap 5 theme).** All **admin** `<select>` enhancement moved to
[Tom Select](https://tom-select.js.org/) 2.6.2 (vendored at `kenedo/external/tom-select-2.6.2/`, AMD id
`tomselect`, BS5 theme CSS loaded for admin views): the dropdown property, the admin list filters, the join
property, the product-tree list select, the calc-code / calc-override / post-install selects, and the generic
`.make-me-chosen` / `.chosen-dropdown` opt-in hooks (kept for compatibility). Tom Select fires the native
`change` event, so `appliesWhen` field visibility and list-filter refresh keep working. In admin CSS,
`.chosen-container*` → `.ts-wrapper`; Chosen's internal multi-select DOM overrides were dropped (Tom Select's
BS5 theme handles it). **The frontend still uses Chosen** (`checkout`, `cart`, `customerform`, `configurator`,
`record`, `general.css`) — unchanged.

> **Custom admin JS that opened selects with Chosen** (`.chosen()`) or read `chosen:updated` must switch to
> Tom Select (`new TomSelect(el, …)`, `el.tomselect.sync()` / `.setValue()`). The `.make-me-chosen` /
> `.chosen-dropdown` opt-in classes still work — they now attach Tom Select.

### Slice 6 — CSS/JS consolidation & anti-bleed sweep

Final cleanup pass. No new renames — this slice tightens what the earlier slices produced:

- **Anti-bleed scoping.** Every *content* rule in `admin.css` is now scoped under `.cb-content` so admin
  styles cannot leak into (or be clobbered by) the host CMS. The `.bs-callout*` family (field-group note
  boxes) and `.cb-usage-message` were the last unscoped content rules and are now `.cb-content …`. The only
  deliberately-unscoped rules that remain are **host-chrome hooks** (`#submenu-box`, `.view-admin`,
  `body.admin.com_configbox`, `.configbox-admin-index*`, `.platform-*`, `.mce-btn`, `body>#footer`,
  `#adminmenuwrap`, container resets) and rules for elements the JS moves outside `.cb-content` at runtime
  (`.kenedo-popup*`, `.ui-tooltip`). Per-view rules already scope through their `.view-admin<name>` wrapper
  class (which sits on the same element as `.cb-content`).
- **Dead CSS removed.** Stale `.tasks-and-filters` rules (the toolbar area is `.cb-toolbar`/`.cb-filters`
  since Slice 1) and a **broken dangling selector** (`select.listing-filter, select.join-select,` that had
  lost its declaration block in an earlier slice and was leaking a `fieldset` rule onto those selectors)
  were removed.

**Task bar flattened to real buttons.** The form/list action bar (rendered by
`KenedoViewHelper::renderTaskItems`, used by every list and form) dropped its `<ul>`/`<li>` scaffolding and
turned the action items into semantic elements:

| Old | New |
|---|---|
| `<div class="cb-tasks"><ul class="cb-task-list"><li class="task task-<name>"><a data-task="…" class="trigger-… btn">` | `<div class="cb-task-buttons"><button type="button" data-task="…" class="trigger-… btn">` |
| `<li class="link"><a href="…" class="trigger-… btn">` (navigation task) | `<a href="…" class="trigger-… btn">` (kept an `<a>` — it is real navigation) |

The container is a flexbox (`.cb-task-buttons { display:flex; gap:.5rem }`); the `<ul>`/`<li>` and the
`.cb-tasks` / `.cb-task-list` / `li.task` / `li.link` / `.task-<name>` classes are gone. Action tasks are now
`<button type="button">` (the `type` matters — it stops the button from submitting the form; the task runs
via the JS click handler). The `.trigger-kenedo-form-task` / `.trigger-kenedo-list-task` hooks and the
`data-task` attribute are unchanged, so custom JS bound to those keeps working. **If your custom CSS targeted
`.cb-tasks ul` / `.cb-task-list` / `li.task`, retarget it to `.cb-task-buttons` and its `> button` / `> a`
children.**

This completes the admin-UI modernization. If your customization still references any legacy admin class,
consult §4 and the per-slice tables above for its `cb-*` replacement; the `.trigger-*` / `.property-*` /
`data-*` contracts and the host-chrome carve-outs listed here are your stable anchors.

### Slice 7 — host stylesheets & one button family

Two follow-ups to Slice 6, both groundwork for host-matched admin theming (a future step where the
admin's basic layout and page elements — buttons, tables, filters, searches — take the host
platform's look):

- **Host-chrome hooks moved out of `admin.css`.** The per-platform sections (`/* Joomla admin CSS
  changes */` etc.) now live in dedicated stylesheets under `assets/css/hosts/`, loaded conditionally
  per platform + area + host admin theme via `getHostStyleSheetUrls()` (see
  `docs/technical/com_configbox_host_stylesheets.md`). Those files also carry anti-bleed counters
  against the host's own CSS (e.g. Atum's table-link and alert styling). Only platform-neutral rules
  remain in `admin.css`.
- **One button family.** Every admin button — list and form task bars, buttons inside form
  properties and editors, filter buttons, and everything inside modals (e.g. the answer edit form) —
  now uses the Bootstrap 5 classes: `.btn .btn-primary` / `.btn .btn-outline-secondary`, with
  `.btn-sm` for inline contexts. The BS3-era `.btn-default` (unstyled under BS5 — those were the
  odd-looking buttons in modals) and the bespoke `.cb-btn-small` are gone from core markup;
  `.cb-btn-small` keeps a deprecated CSS alias approximating the `.btn-sm .btn-outline-secondary`
  look so old customizations stay presentable. Intra-list task buttons size via the `--bs-btn-*`
  tokens instead of hardcoded padding. **If your customization emits admin buttons, use the BS5
  variants above — a future host theme restyles buttons by re-defining `--bs-btn-*` tokens, and
  bespoke button CSS will not pick that up.**

<!-- SLICE-CHANGELOG-END -->

---

## 4. Class rename reference

> Populated as slices ship. `→` means "replaced by"; **KEEP** means the class is unchanged.

### Stable (no change)
- `.trigger-*` — **KEEP** (JS hooks).
- `property-name-<name>`, `property-type-<type>`, `property-label`, `property-body` — **KEEP**.
- All `data-*` attributes — **KEEP**.

### List (Slice 1)
- `kenedo-listing-form` → `cb-list`
- `kenedo-listing` (table) → `cb-list-table` (also carries BS5 `table`)
- `sortable-listing` / `unsortable-listing` → `cb-list--sortable` / `cb-list--static`
- `item-row` → `cb-list-row`
- `field-<prop>` (cells) → `cb-cell-<prop>`
- `kenedo-title-and-tasks` → `cb-toolbar`
- `kenedo-page-title` → `cb-title`
- `kenedo-filters` / `kenedo-filter` → `cb-filters` / `cb-filter`
- `kenedo-pagination` → `cb-pagination` (also carries BS5 `pagination`)
- `listing-data` → `cb-list-data` (data-attrs unchanged)
- `kenedo-messages(-error/-notice)` → `cb-messages(-error/-notice)` (BS5 `alert`)

### Form & field groups (Slice 2)
- `kenedo-details-form` → `cb-form`
- `kenedo-properties` → `cb-fields`
- `kenedo-property` → `cb-field` (BS4 `form-group` dropped from the wrapper)
- `property-group` → `cb-field-group` (inner `-legend/-content/-properties` → `cb-field-group-legend/-content/-body`)
- `property-group-opened/-closed` → `cb-field-group--open/--closed`
- `property-group-using-toggles` → `cb-field-group--toggles`; `property-group-toggle-state` → `cb-field-group-state`
- `kenedo-item-usage/-usage-message` → `cb-item-usage/cb-usage-message`; `kenedo-candelete-usage-entry-*` → `cb-usage-entry-*`
- `kenedo-hidden-fields` → `cb-hidden-fields`
- **Kept:** `property-name-<name>` (still the wrapper `id`), `property-type-<type>`, `property-label`,
  `property-body`, `invisible-field`, `required` — and the `.property-type-*` widget internals (Slice 3).

### Property field templates + asset extraction (Slice 3)
- Per-type assets now live in `assets/css/properties/<type>.css` and `assets/javascript/properties/<type>.js`,
  wired via `KenedoProperty::getStyleSheetUrls()` / `getJsInitCallsOnce()` / `getJsInitCallsEach()`.
- translatable: `translations`→`cb-translations`, `translation(-label)`→`cb-translation(-label)`,
  `language-switcher(s)`→`cb-lang-switcher(s)`, `using-editors`→`cb-using-editors`.
- file/image: `file-*`→`cb-file-*`; `highlighted/no-file-text`→`cb-file-missing/cb-file-none`;
  `show-file-uploader`/`file-upload-cancel`→`trigger-show-file-uploader`/`trigger-file-upload-cancel`.
- multiselect: `multiselect-toggles`→`cb-multiselect-toggles`, `extended-multiselect`→`cb-multiselect-extended`,
  `checkbox-field/-item/-label`→`cb-checkbox-field/-item/-label`.
- shapediver: `sd-note-bad-*`→`cb-sd-note-bad-*`, `parameter-selection-help*`→`cb-sd-parameter-selection-help*`.
- **Kept:** `.kenedo-html-editor`, `.kenedo-datepicker` (Slice 5), `.radio-button-label` (shared w/ frontend).
- **Not extracted:** `paymentmethodparams`, `usergroupdiscount` (stay in `admin.css`, view-scoped).

### Buttons & host CSS (Slice 7)
- `btn btn-default` (BS3 relic, admin markup) → `btn btn-outline-secondary` (inline contexts add `btn-sm`)
- `cb-btn-small` → `btn btn-sm btn-outline-secondary` (deprecated CSS alias remains for custom markup)
- `cb-list-filter-btn btn btn-light` → `cb-list-filter-btn btn btn-outline-secondary`
- `pull-right` (dead BS3 utility in admin templates) → `float-end`
- Host-specific rules left `admin.css` for `assets/css/hosts/<platform>-<area>[-<theme>].css` —
  selectors unchanged, only the file moved (see `docs/technical/com_configbox_host_stylesheets.md`).

_(Further slices extend this table.)_

---

## 5. Getting help

If a customization breaks in a way this guide doesn't cover, note the exact class/selector and the view it
occurs in — the stable `.trigger-*`/`.property-*`/`data-*` contracts should give you a reliable anchor to
re-attach to.
