Skip to content

Slot menus

A menu with real item slots, like a chest. GaldurMenu places the slots and handles Shift-click on both sides; GaldurContainerScreen draws the themed screen.

⏱ 7 minGaldur UI 0.1.0Client & server

How it fits together

A slot menu has two halves, as in vanilla Minecraft:

ClassSideRole
GaldurMenuclient and serverThe logic: which slots exist, where, and how Shift-click moves items.
GaldurContainerScreenclientThe screen: theme panel, slot frames, titles, opening animation.

api.menu is the only Galdur UI package that loads on a dedicated server.

Write the menu

Extend GaldurMenu, add the container slots, then the player inventory:

CrateMenu.java
public class CrateMenu extends GaldurMenu {    private final Container crate;    public CrateMenu(int id, Inventory player) {               // client side        this(id, player, new SimpleContainer(27));    }    public CrateMenu(int id, Inventory player, Container crate) { // server side        super(MY_MENUS.CRATE.get(), id);        this.crate = crate;        addSlotGrid(crate, 0, 9, 3, 8, 18);   // container slots first        addPlayerInventory(player, 8, 84);    // player inventory last    }    @Override    public boolean stillValid(Player player) {        return crate.stillValid(player);    }}
Order matters

Add the container slots first (addSlotGrid or addSlot), then the player inventory (addPlayerInventory), once. Every slot added before the player inventory counts as a container slot for Shift-click. Adding a grid after the inventory throws an IllegalStateException.

Coordinates

Coordinates are Minecraft's: GUI pixels from the top-left corner of the menu panel, pointing at the top-left corner of the 16 × 16 item. The slot frame extends one pixel around it.

ConstantValueMeaning
SLOT_SIZE18Distance between two neighbouring slots: 16 for the item, 2 for the frames.
HOTBAR_GAP4Vertical gap between the three inventory rows and the hotbar.

addSlotGrid(container, firstIndex, columns, rows, x, y) fills row by row, left to right. addPlayerInventory(inventory, x, y) adds three rows of nine, then the hotbar HOTBAR_GAP pixels lower.

Register the menu type

Register the menu type as usual, with a DeferredRegister on the mod bus:

MyMenus.java
private static final DeferredRegister<MenuType<?>> MENUS = DeferredRegister.create(Registries.MENU, MyMod.MODID);public static final DeferredHolder<MenuType<?>, MenuType<CrateMenu>> CRATE =        MENUS.register("crate", () -> new MenuType<>(CrateMenu::new, FeatureFlags.DEFAULT_FLAGS));

The client constructor CrateMenu(int, Inventory) is the one MenuType calls on the client. On the server, open the menu with your container, for instance player.openMenu(new SimpleMenuProvider((id, inv, p) -> new CrateMenu(id, inv, crate), title)).

Register the screen

Client side, on the mod bus. factory() gives a screen constructor without writing a subclass:

MyModClient.java
modEventBus.addListener(RegisterMenuScreensEvent.class,        event -> event.register(MY_MENUS.CRATE.get(), GaldurContainerScreen.factory()));

Shift-click, drag and drop, number keys, item tooltips, the theme panel and the slot frames work without more code. factory() works for any menu, vanilla ones included.

What the screen does for you

  • Panel size is derived from the slots: the margin left of the first slot is repeated on the right and at the bottom. A menu without slots gets the size of a vanilla chest (176 × 166).
  • "Inventory" label sits right above the player inventory when the menu has one, and is hidden otherwise.
  • Hover: the hovered slot gets a translucent accent veil and an accent_hover outline, as does every slot targeted by a drag-spread.
  • Title in the brand font (Title font).
  • Opening: the panel rises slightly when the screen opens.
  • Narration: the hovered slot's item is read ("Iron Ingot, 32"), which Minecraft does not do.

Customise the screen

Subclass GaldurContainerScreen to force a panel size, or to add content:

CrateScreen.java
public class CrateScreen extends GaldurContainerScreen<CrateMenu> {    public CrateScreen(CrateMenu menu, Inventory inventory, Component title) {        super(menu, inventory, title, 176, 190);   // forced panel size    }    @Override    protected void init() {        super.init();        // add widgets here, relative to leftPos / topPos    }}

Override renderBg or renderLabels to draw more. If a button or a side tab sticks out of the panel, return its area from getExclusionZones() so JEI and EMI keep it clear.

Next: show thousands of items without real slots with Item grids & terminals.

© 2026 Galdur Studio · galdurstudio.com · Discord · LGPL-3.0-onlyNot an official Minecraft product. Not approved by or associated with Mojang or Microsoft.