diff --git a/core/js/src/combobox.ts b/core/js/src/combobox.ts index 8ba9fe377..018b76c86 100644 --- a/core/js/src/combobox.ts +++ b/core/js/src/combobox.ts @@ -305,26 +305,14 @@ class Combobox extends BaseComponent { _createToggle(select: HTMLSelectElement): HTMLElement { const multiple = select.multiple - const toggle = document.createElement(multiple ? 'div' : 'button') + const toggle = document.createElement('button') + toggle.type = 'button' toggle.className = `${select.className} form-select combobox-toggle` toggle.append(Object.assign(document.createElement('span'), { className: 'combobox-value' })) - if (multiple) { - toggle.setAttribute('role', 'combobox') - toggle.tabIndex = 0 - } else { - toggle.setAttribute('type', 'button') - } - if (select.disabled) { - toggle.classList.add('disabled') - toggle.setAttribute('aria-disabled', 'true') - toggle.tabIndex = -1 - - if (!multiple) { - toggle.setAttribute('disabled', '') - } + toggle.disabled = true } const label = select.id ? document.querySelector(`label[for="${CSS.escape(select.id)}"]`) : null @@ -638,6 +626,11 @@ class Combobox extends BaseComponent { } nodes.push(Object.assign(document.createElement('span'), { className: 'text-truncate', textContent: this._getItemLabel(item) })) + + for (const addon of SelectorEngine.children(item, 'kbd, .badge')) { + nodes.push(addon.cloneNode(true)) + } + return nodes } diff --git a/core/js/tests/unit/combobox.spec.ts b/core/js/tests/unit/combobox.spec.ts index 1540e1aed..289118ab0 100644 --- a/core/js/tests/unit/combobox.spec.ts +++ b/core/js/tests/unit/combobox.spec.ts @@ -312,6 +312,17 @@ describe('Combobox', () => { expect(menu.classList.contains('show')).toBe(false) }) + it('should show a shortcut and a badge of the item in the toggle', () => { + fixtureEl.innerHTML = markup().replace('>Alpha', '>Alphactrl + A3') + const toggle = fixtureEl.querySelector('.combobox-toggle')! + new Combobox(toggle) + item('a').click() + + expect(toggle.querySelector('.combobox-value kbd')!.textContent).toBe('ctrl + A') + expect(toggle.querySelector('.combobox-value .badge')!.textContent).toBe('3') + expect(toggle.querySelector('.combobox-value .text-truncate')!.textContent).toBe('Alpha') + }) + it('should show the option markup in the toggle', () => { const { menu, toggle, combobox } = setupSelect() combobox.show() diff --git a/core/scss/ui/forms/_combobox.scss b/core/scss/ui/forms/_combobox.scss index 4990d8a2c..6f83b5f64 100644 --- a/core/scss/ui/forms/_combobox.scss +++ b/core/scss/ui/forms/_combobox.scss @@ -5,6 +5,7 @@ --combobox-menu-max-height: #{$combobox-menu-max-height}; --combobox-placeholder-color: #{$input-placeholder-color}; // scss-docs-end combobox-css-vars + --dropdown-item-icon-size: #{$icon-size}; text-align: start; cursor: pointer; @@ -31,6 +32,13 @@ } } +.combobox-toggle .dropdown-item-indicator > img, +.combobox-menu .dropdown-item-indicator > img { + width: var(--dropdown-item-icon-size); + height: var(--dropdown-item-icon-size); + object-fit: contain; +} + .combobox-menu { z-index: $zindex-popover; max-height: var(--combobox-menu-max-height, #{$combobox-menu-max-height}); @@ -57,6 +65,8 @@ gap: 0.5rem; align-items: center; min-width: 0; + padding: 4px; + margin: -4px; overflow: hidden; white-space: nowrap; } diff --git a/docs/content/ui/forms/combobox.mdx b/docs/content/ui/forms/combobox.mdx index a7ba3e120..b499cc8e5 100644 --- a/docs/content/ui/forms/combobox.mdx +++ b/docs/content/ui/forms/combobox.mdx @@ -7,6 +7,7 @@ description: Add a customizable combobox (select replacement) with search, multi related: [/ui/forms/elements, /ui/components/dropdowns, /ui/forms/validation] source: core/scss/ui/forms/_combobox.scss css-vars: combobox +css-plugins: [flags, payments] classnames: component: - class: combobox-toggle @@ -300,9 +301,9 @@ Put markup in a `data-custom-properties` attribute to show an avatar, flag or ba
@@ -333,6 +334,291 @@ tabler.Combobox.getInstance(select).refresh() | `sync()` | `refresh()` | | `create`, remote `load`, other plugins | Not supported yet | +## Examples + +Since the items are ordinary HTML, a combobox can show much more than text. On a ` + + + + + + + + + + + + + + + + +### Payment methods + +Use the [payments](/payments/css) icons to pick a card or a wallet. + + +
+ +
+
+ +### Keyboard shortcuts + +Wrap the label in `.dropdown-item-label` and add a `` after it. The shortcut is shown in the toggle too, once the item is chosen. + + +
+ + +
+
+ +### Avatars + +Show the person next to the name. + + +
+ +
+
+ +Add a name and an email with `.dropdown-item-content` and `.dropdown-item-description`. + + +
+ + +
+
+ +On a multiple ` + + + + + + + + + + +### Status + +An empty [badge](/ui/components/badge) works as a status dot. + + +
+ + +
+
+ +### Logos + +Any image works, for example the browser logos. + + +
+ +
+
+ +### Icons with descriptions + +Put an image in `.dropdown-item-indicator` and a second line in `.dropdown-item-description`. + + +
+ + +
+
+ +### Badges + +Push a badge to the end of the item with `.ms-auto`, for example to show a count. Like a shortcut, a badge that is a direct child of the item is shown in the toggle too. + + +
+ + +
+
+ ## Form submission When `data-bs-name` is set, a hidden `` with that name is inserted before the toggle and updated on every change.