thermal-dropdown
A button that opens a floating list of actions. Click the button again or click outside the list to close it. No context providers are required.
Attributes
interactive
Set to "off" to disable the invoker. This uses "on" and "off", not "true" and "false". Only the exact value "off" prevents toggling; use the documented values rather than an empty attribute.
This does not close an already open list or prevent JavaScript from calling setOpen().
<thermal-dropdown interactive="off">
<span slot="invoker">Unavailable</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
</thermal-dropdown>variant
Appearance of the invoker button, not the options. Without this attribute, the button uses its standard light appearance. "default" and "breadcrumb" also use the base appearance; "text" is supported by the button's CSS and removes its background, border and padding.
<thermal-dropdown variant="primary">
<span slot="invoker">Primary actions</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
</thermal-dropdown>
<thermal-dropdown variant="foreground">
<span slot="invoker">Foreground actions</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
</thermal-dropdown>size
Size of the invoker button. Omitted and "md" use the base button size. Options keep their own sizes.
<thermal-dropdown size="sm">
<span slot="invoker">Small</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
</thermal-dropdown>
<thermal-dropdown size="lg">
<span slot="invoker">Large</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
</thermal-dropdown>tooltip
Tooltip displayed when the invoker is hovered or focused. Omitted or empty values show no tooltip. Tooltips for individual options must be set on their buttons separately.
<thermal-dropdown tooltip="Choose a file action">
<span slot="invoker">File actions</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
</thermal-dropdown>icon + iconstyle
An icon displayed before the invoker label. The two attributes work together:
icon(string) – name of a built-in icon. Unknown names are ignored.iconstyle('outline' | 'solid' | 'mini' | 'micro', defaultoutline) – style of that icon. It has no effect withouticon.
Not every icon exists in every style; an unavailable combination renders no icon. The dropdown arrow is shown independently of the icon.
See Icons for the complete catalog with previews and usage across components.
<thermal-dropdown icon="download">
<span slot="invoker">Outline (default)</span>
<div slot="option"><thermal-btn>Download image</thermal-btn></div>
</thermal-dropdown>
<thermal-dropdown icon="download" iconstyle="micro">
<span slot="invoker">Micro</span>
<div slot="option"><thermal-btn>Download image</thermal-btn></div>
</thermal-dropdown>There are no additional component-specific attributes inherited from the base class. Standard global HTML attributes such as id, class and style are not listed here. A label attribute does not set the invoker text: use the invoker slot.
Slots
invokerreplaces the default text "Dropdown" inside the built-in button. Use text content in aspan, or other non-interactive content. Unlike thermal-dialog, this does not replace the entire invoker: avoid nesting another button or link inside it.optionsupplies the list entries. Use a separatediv slot="option"containing a button for each action, as shown below.
<thermal-dropdown>
<span slot="invoker">Actions</span>
<div slot="option"><thermal-btn>First action</thermal-btn></div>
<div slot="option"><thermal-btn>Second action</thermal-btn></div>
</thermal-dropdown>Automatic closing: the component attaches close listeners to the child nodes of each option element during its first render. With the wrapper structure above, clicking the button closes the list. A button placed directly in slot="option" does not automatically close it. Options inserted later do not receive these automatic close listeners; call setClose() in their handlers if needed.
The list opens below the invoker and can flip or shift to fit the viewport. Its position is recalculated when isOpen changes, not continuously during scrolling or resizing.
JavaScript API
isOpenis the string"open"or"close", reflected toisopen.setOpen()opens the list, even withinteractive="off".setClose()closes the list.toggle()toggles the list unlessinteractive="off".
Before opening programmatically for the first time, await customElements.whenDefined('thermal-dropdown'), obtain the element and await its Lit updateComplete promise. Registration alone does not mean its internal button and option container have rendered.
The component does not emit a custom selection event. Handle the standard click event on each option button.
Examples
Load the webcomponents bundle as described in Usage in the browser before using these examples.
Choose an action
Each option updates the output with an HTML onclick handler. The wrapper structure makes the list close automatically. The handler checks disabled because listeners on the button itself still run for disabled buttons. Clicking a disabled option may still close the list, but does not update the output.
<thermal-dropdown>
<span slot="invoker">Choose an action</span>
<div slot="option">
<thermal-btn onclick="
if (event.defaultPrevented || this.getAttribute('disabled') === 'true') return;
this.closest('thermal-dropdown').nextElementSibling.textContent = 'Download selected.';
">Download</thermal-btn>
</div>
<div slot="option">
<thermal-btn disabled="true" onclick="
if (event.defaultPrevented || this.getAttribute('disabled') === 'true') return;
this.closest('thermal-dropdown').nextElementSibling.textContent = 'Delete selected.';
">Delete (unavailable)</thermal-btn>
</div>
</thermal-dropdown>
<output aria-live="polite">No action selected.</output>Complete HTML document
This example loads the webcomponents IIFE bundle and attaches a named click handler. Replace the placeholder script URL with your own.
DOMContentLoaded waits for the body to be parsed and the deferred bundle to run. customElements.whenDefined() waits for the tags to be registered; it does not wait for rendering, images or data fetching. Here the list opens only after the user clicks its invoker.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dropdown example</title>
<script defer src="/path-to-your-script/labirthermal.iife.js"></script>
</head>
<body>
<script>
function selectAction(event) {
const button = event.currentTarget;
if (
event.defaultPrevented ||
button.getAttribute('disabled') === 'true'
) {
return;
}
document.getElementById('action-result').textContent =
'Selected: ' + button.textContent.trim();
}
document.addEventListener('DOMContentLoaded', async () => {
await Promise.all([
customElements.whenDefined('thermal-dropdown'),
customElements.whenDefined('thermal-btn'),
]);
const dropdown = document.getElementById('file-actions');
for (const button of dropdown.querySelectorAll('[slot="option"] > thermal-btn')) {
button.addEventListener('click', selectAction);
}
});
</script>
<thermal-dropdown id="file-actions" icon="download">
<span slot="invoker">File actions</span>
<div slot="option"><thermal-btn>Download</thermal-btn></div>
<div slot="option"><thermal-btn>Show details</thermal-btn></div>
<div slot="option"><thermal-btn disabled="true">Delete</thermal-btn></div>
</thermal-dropdown>
<output id="action-result" aria-live="polite">No action selected.</output>
</body>
</html>The invoker and option buttons can be focused with Tab and activated with Enter or Space. This is not a native select: no arrow-key navigation or Escape handler is implemented.