Skip to content
ssbaxys edited this page Oct 26, 2026 · 1 revision

Dropdowns, tooltips, context and radial menus, calendar.

Dropdowns, tooltips, the radial menu and the calendar live in the popup layer of UiRoot: they are drawn above the content and get the mouse and keys first. Escape closes the top popup, and so does a click outside.

  • root.showPopup(element, x, y) / closePopup / popups() are popups (menus, lists);
  • root.showOverlay(element, x, y) / overlays() are passive overlays (tooltips): drawn above all popups, but the mouse passes through them, they get no keys, and a click outside doesn't close them;
  • root.movePopup(element, x, y) moves an open popup or overlay (a tooltip following the mouse);
  • a key release (keyUp) also goes to the top popup first; that's how the radial menu picks an item.

Dropdown (Select<T>): a field with the current value and an arrow; the list opens below the field (above it if there is no room) with a vertical reveal. A long list scrolls with the wheel (only visible rows are drawn), a search line filters options by substring ignoring case, and items can have item icons. Keyboard: when closed, Enter, Space or Alt+↓ open it, ↑/↓ change the value in place, a letter jumps to an option; when open, ↑/↓, PageUp/PageDown, Home/End, Enter picks, Escape closes.

Signal<String> ore = Signal.of("minecraft:diamond");
new Select<>(ore, List.of("minecraft:diamond", "minecraft:emerald", "minecraft:gold_ingot"))
        .labels(id -> names.get(id))   // option label
        .icons(id -> id)               // icon is an item id (or null)
        .searchable(true)              // search line
        .maxRows(7)                    // visible rows, then scrolling
        .placeholder("Pick an ore")    // while the value is null
        .onChange(id -> log(id));
Select.of(difficulty, Difficulty.values()).labels(Difficulty::title);

Styles: "select" is the field (like "field"; an open list is the Select.OPEN state), "dropdown" is the list card (background, border, shadow; the highlighted row uses ACCENT_COLOR, text uses TEXT_COLOR).

Tooltips (Tooltip, Tooltips): appear after a hover delay (0.5 s), follow the mouse and flip at the screen edges. A mouse press hides the tooltip until the next move; only one tooltip is visible, the one of the deepest hovered element. An element's tooltip disappears when the element is removed from the tree.

button.tooltip("Save world\nCtrl+S");                             // text, lines separated by \n
button.tooltip(Tooltip.Kind.MODERN, "Theme card");                // custom look
icon.tooltipMarkdown("**Diamond** ![](item:minecraft:diamond)");  // Markdown
Tooltips.attach(slot, () -> buildCard(slot))                      // any element, built when shown
        .kind(Tooltip.Kind.MODERN).follow(false).delay(0.2f).maxWidth(220);
Tooltips.attach(label, "on any UiElement");                       // a label becomes hoverable too
Tooltips.of(button).text("New text");                             // an open tooltip updates immediately
Tooltips.detach(button);
Tooltips.setDefaultKind(Tooltip.Kind.MODERN);                     // default look and delay
Tooltips.setDefaultDelay(0.3f);

Looks: VANILLA is like the game: almost black background 0xF0100010, a purple gradient border 0x505000FF → 0x5028007F, cut corners, white text with a shadow, 2 extra pixels after the first line (the name) (style "tooltip-vanilla": BACKGROUND, BORDER_BRUSH, TEXT_COLOR, PADDING); MODERN is a theme card with rounded corners, a border, a shadow and a soft fade-in (style "tooltip" on the SURFACE, BORDER, SHADOW, TEXT, CORNER tokens). follow(false) places the tooltip centered below the element (above it if there is no room). show() / hide() show and hide it from code.

Radial menu (RadialMenu): sectors around the point where it opened. A sector is picked by the mouse direction from the center (even outside the ring); the hovered one slides out and turns accent-colored, with its label in the center. An item can open a submenu (a small triangle at the sector edge); right click, a click in the center, Backspace or Escape go back. Arrow keys cycle sectors, Enter picks, digits 1–9 pick an item by number.

RadialMenu wheel = new RadialMenu()
        .title("Actions")
        .item("Sword", "minecraft:diamond_sword", this::sword)
        .item("Torch", this::torch)                                  // no icon: the label sits in the sector
        .submenu("Food", "minecraft:apple",
                RadialMenu.Item.of("Bread", this::bread).icon("minecraft:bread"),
                RadialMenu.Item.of("Cake", this::cake).enabled(false))
        .radius(30, 88);
wheel.show(root, mouseX, mouseY);                       // pick with a click
wheel.showHeld(root, mouseX, mouseY, Keys.R);           // while R is held: releasing picks
RadialMenu.bindKey(screenContent, Keys.R, this::wheel); // R pressed over the element (or its focused descendant)
RadialMenu.bindRightClick(area, this::wheel);           // right click over the element

The menu covers the whole screen (the style background dims it). Style "radial-menu": BACKGROUND is the dimming, PopupStyles.WEDGE_COLOR (radial-wedge-color) the sectors and center, ACCENT_COLOR the hovered sector, TEXT_COLOR the labels. bindKey fires when the key reaches the element: without focus, keys go to root.content().

Key binding (KeyBindField): a click or Enter makes the field wait for a key ("> Press a key <" pulsing); the next key (any, even Tab) becomes the value, Escape and losing focus cancel waiting, right click or Delete restore defaultKey. The value is a GLFW code in a Signal<Integer>, KeyBindField.NONE means unset. KeyBindField.keyName(code) gives a name ("Space", "Left Shift", "F5", "Num 7"), parseKey("space") goes back. Style "field keybind", waiting is the KeyBindField.LISTENING state.

Dates (DatePicker, CalendarView): a 12.10.2026 field opens a month calendar in a popup. Weeks start on Monday, the selected day is filled with the accent, today is outlined, days of neighboring months are dimmed, days outside range(min, max) are disabled. Months change with the header arrows, the wheel and PageUp/PageDown (the grid briefly slides), days with the arrows, Enter picks. CalendarView can also be placed directly in the UI.

Signal<LocalDate> date = Signal.of(LocalDate.now());
new DatePicker(date).range(LocalDate.now(), null).format(DateTimeFormatter.ofPattern("d.M.yy"));
new CalendarView(date).onPick(d -> log(d));

Styles: the field is "select", the popup calendar is "dropdown calendar", the inline one is "calendar". All the new classes exist in Theme.dark(), Theme.light() and ModernTheme and are built on tokens. In markup: the <select>, <keybind>, <date-picker>, <calendar> tags and the tooltip attribute (see HTML and CSS). An example of everything together is the showcase page PopupsPage.


← Widget Catalog · English home · Forms →

Clone this wiki locally