Skip to content

Dropdown

JS

A dropdown is a short list of choices attached to a trigger: sort order, a row menu. It’s not a form <select>. Use the native control when you need a form value.

Give the host an id and hand it a trigger and its items:

<k-dropdown id="sort" class="k-dropdown"></k-dropdown>
document.getElementById('sort').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};

The element builds the trigger, the menu, the items, and the ARIA. There is no linked content here, since a menu is a list of labels rather than markup you wrote. An item with an href becomes an anchor instead of a button. Pass select: true when the pick should replace the trigger text, which is the usual case for a sort menu. Leave it off for a row of actions.

The trigger is a secondary button. The open menu sits below it, outside any overflow on a parent. It toggles open, closes on an outside click or Escape, and moves through items with the keyboard. Setting options rebuilds the menu, except when only trigger changed, which relabels the button in place.

ClassTypeDescription
k-dropdowncomponentThe one class you write. The element generates the trigger, menu, and items inside it.
k-dropdown--endmodifierAligns the menu to the inline end of the host, for a trigger sitting on the right.
Generated classes
ClassTypeDescription
k-dropdown__triggerpartThe button that opens the menu. Also carries k-btn k-btn--secondary and a chevron-down icon.
k-dropdown__menupartThe list of items. Hidden until open.
k-dropdown__itempartOne choice. A button, or an anchor when the item has an href.
OptionTypeDefaultDescription
triggerstring—Visible text on the generated button. Required.
itemsKDropdownItem[]—One entry per choice, in menu order.
items[].labelstring—Item text. Required.
items[].hrefstring—Makes the item an anchor. It still fires k-change before it navigates.
selectboolean—Writes the picked item onto the trigger. For sort menus and the like.
PropertyTypeDescription
optionsKDropdownOptions | nullRead/write. Writing rebuilds the menu, or relabels the trigger when that is the only change.
countnumberRead-only. Number of items.
labelsstring[]Read-only. Item labels in order.
openbooleanRead-only. True while the menu is showing.
triggerHTMLElement | nullRead-only. The generated trigger.
menuHTMLElement | nullRead-only. The generated menu.
MethodReturnsDescription
toggle(open)voidOpens or closes the menu. Omit the argument to flip the current state.
openMenu()voidOpens the menu.
closeMenu()voidCloses the menu.
getItems()HTMLElement[]Copy of the item nodes.
getItem(index)HTMLElement | nullThe item at an index.
focusItem(index)booleanOpens the menu if needed and focuses an item. Returns false on a miss.
select(index)voidPicks an item the way a click does: closes the menu and fires k-change.
selectByLabel(label)booleanPicks the first item whose label matches. Returns false on a miss.
addOption(item, at)voidInserts an item, appending when at is left out.
removeOption(index)voidDrops an item.
updateOption(index, patch)voidMerges a partial item into the one at that index.
refresh()voidRebuilds the trigger and menu from the current options.
disconnect()voidRemoves listeners, including the document-level outside-click handler.

Picking an item dispatches k-change with { index, label, href }, and the event bubbles. href is null for an item without one. The event fires on a click, on a keyboard activation, and on select(), so a single listener covers every path.

Open it, then pick an item or click away.

<k-dropdown id="sort" class="k-dropdown"></k-dropdown>
import 'k-web-ui/js';
document.getElementById('sort').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};
import { Component, CUSTOM_ELEMENTS_SCHEMA, type AfterViewInit } from '@angular/core';
import 'k-web-ui/js';
@Component({
selector: 'app-example',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<k-dropdown id="sort" class="k-dropdown"></k-dropdown>
`,
})
export class ExampleComponent implements AfterViewInit {
ngAfterViewInit() {
document.getElementById('sort').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};
}
}
import { useEffect } from 'react';
import 'k-web-ui/js';
export function Example() {
useEffect(() => {
document.getElementById('sort').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};
}, []);
return (
<>
<k-dropdown id="sort" className="k-dropdown"></k-dropdown>
</>
);
}

k-dropdown--end pins the menu to the inline end.

<k-dropdown id="sort-end" class="k-dropdown k-dropdown--end"></k-dropdown>
import 'k-web-ui/js';
document.getElementById('sort-end').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};
import { Component, CUSTOM_ELEMENTS_SCHEMA, type AfterViewInit } from '@angular/core';
import 'k-web-ui/js';
@Component({
selector: 'app-example',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<k-dropdown id="sort-end" class="k-dropdown k-dropdown--end"></k-dropdown>
`,
})
export class ExampleComponent implements AfterViewInit {
ngAfterViewInit() {
document.getElementById('sort-end').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};
}
}
import { useEffect } from 'react';
import 'k-web-ui/js';
export function Example() {
useEffect(() => {
document.getElementById('sort-end').options = {
trigger: 'Sort',
items: [{ label: 'Name' }, { label: 'Date' }, { label: 'Size' }],
select: true,
};
}, []);
return (
<>
<k-dropdown id="sort-end" className="k-dropdown k-dropdown--end"></k-dropdown>
</>
);
}

The element sets aria-haspopup="menu" and aria-expanded on the trigger, role="menu" on the menu, and role="menuitem" on items. The menu id comes from the host id, so the trigger gets aria-controls. Arrow keys open and move. Home and End jump. Escape closes and returns focus to the trigger.

Do

  • Give the host a unique id. The generated ids derive from it.
  • Set options with a trigger and its items.
  • Listen for k-change to react to a pick.

Don’t

  • Hand-write the trigger and menu. The element builds them.
  • Use this as a form <select>.
  • Open a modal for three actions.