GUI Concepts

GUI elements are represented as instances of UIWidget. The GUI is structured like a tree; every widget can have other widgets as children.

The root of the tree is the UIManager. The UIManager connects the user interactions with the GUI. Read more about User-interface events.

Classes of arcade’s GUI code are prefixed with UI- to make them easy to identify and search for in autocompletion.


Following classes provide the basic structure of the GUI.


UIManager is the starting point for the GUI.

To use the GUI, you need to create a UIManager instance and call its add() method to add widgets to the GUI. Each View should have its own UIManager. (If you don’t use views, you can use a single UIManager for the window.)

The UIManager does not react to any user input initially. You have to call enable() within on_show_view(). And disable it with disable() within on_hide_view().

To draw the GUI, call draw() within the on_draw() method.


The UIWidget class is the core of arcade’s GUI system. Widgets specify the behavior and graphical representation of any UI element, such as buttons or labels.

User interaction with widgets is processed within on_event().

A UIWidget has following properties.


A tuple with four slots. The first two are x and y coordinates (bottom left of the widget), and the last two are width and height.


Child widgets rendered within this widget. A UIWidget will not move or resize its children; use a UILayout instead.


A tuple of two normalized floats (0.0-1.0) describing the portion of the parent’s width and height this widget prefers to occupy.


# Prefer to take up all space within the parent
widget.size_hint = (1.0, 1.0)

# Prefer to take up the full width & half the height of the parent
widget.size_hint = (1.0, 0.5)
# Prefer using 1/10th of the available width & height
widget.size_hint = (0.1, 0.1)

A tuple of two integers defining the minimum width and height of the widget. These values should be taken into account by UILayout when a size_hint is given for the axis.


A tuple of two integers defining the maximum width and height of the widget. These values should be taken into account by UILayout when a size_hint is given for the axis.


Size hints do nothing on their own!

They are hints to UILayout instances, which may choose to use or ignore them.


UILayout are widgets, which reserve the right to move or resize children. They might respect special properties of a widget like size_hint, size_hint_min, or size_hint_max.

The arcade.gui.UILayout must only resizes a child’s dimension (x or y axis) if size_hint provides a value for the axis, which is not None for the dimension.


The GUI is optimised to be as performant as possible. This means that the GUI splits up the positioning and rendering of each widget and drawing of the result on screen.

Widgets are positioned and then rendered into a framebuffer (something like a window sized image), which is only updated if a widget changed and requested rendering (via trigger_render() or trigger_full_render()).

During draw(), will check if updates are required and finally draws on screen.

Layouting and Rendering

UIManager triggers layouting and rendering of the GUI before the actual frame draw (if necessary). This way, the GUI can adjust to multiple changes only once.

Layouting is a two-step process: 1. Prepare layout, which prepares children and updates own values 2. Do layout, which actually sets the position and size of the children

Rendering is not executed during each draw call. Changes to following widget properties will trigger rendering:

  • rect

  • children

  • background

  • border_width, border_color

  • padding

  • widget-specific properties (like text, texture, …)

do_render() is called recursively if rendering was requested via trigger_render(). In case widgets have to request their parents to render, use arcade.gui.UIWidget.trigger_full_render().

The widget has to draw itself and child widgets within do_render(). Due to the deferred functionality render does not have to check any dirty variables, as long as state changes use the trigger_full_render() method.

For widgets, that might have transparent areas, they have to request a full rendering.


Enforced rendering of the whole GUI might be very expensive!

Layout Algorithm by example

arcade.gui.UIManager triggers the layout and render process right before the actual frame draw. This opens the possibility to adjust to multiple changes only once.

Example: Executed steps within UIBoxLayout:

  1. prepare_layout() updates own size_hints

  2. do_layout()
    1. Collect current size, size_hint, size_hint_min of children

    2. Calculate the new position and sizes

    3. Set position and size of children

  3. Recursively call do_layout on child layouts (last step in do_layout())

┌─────────┐          ┌────────┐                      ┌────────┐
│UIManager│          │UILayout│                      │children│
└────┬────┘          └───┬────┘                      └───┬────┘
     │ prepare_layout() ┌┴┐                              │
     │─────────────────>│ │                              │
     │                  │ │                              │
     │     ╔═══════╤════╪═╪══════════════════════════════╪══════════════╗
     │     ║ LOOP  │  sub layouts                        │              ║
     │     ╟───────┘    │ │                              │              ║
     │     ║            │ │       prepare_layout()       │              ║
     │     ║            │ │ ─────────────────────────────>              ║
     │     ╚════════════╪═╪══════════════════════════════╪══════════════╝
     │                  │ │                              │
     │<─ ─ ─ ─ ─ ─ ─ ─ ─│ │                              │
     │                  │ │                              │
     │ do_layout()      │ │                              │
     │─────────────────>│ │                              │
     │     ╔════════════╪═╪════╤═════════════════════════╪══════════════╗
     │     ║ place children    │                         │              ║
     │     ╟───────────────────┘                         │              ║
     │     ║            │ │   use size, size_hint, ...   │              ║
     │     ║            │ │ <─────────────────────────────              ║
     │     ║            │ │                              │              ║
     │     ║            │ │       set size and pos       │              ║
     │     ║            │ │ ─────────────────────────────>              ║
     │     ╚════════════╪═╪══════════════════════════════╪══════════════╝
     │                  │ │                              │
     │                  │ │                              │
     │     ╔═══════╤════╪═╪══════════════════════════════╪══════════════╗
     │     ║ LOOP  │  sub layouts                        │              ║
     │     ╟───────┘    │ │                              │              ║
     │     ║            │ │          do_layout()         │              ║
     │     ║            │ │ ─────────────────────────────>              ║
     │     ╚════════════╪═╪══════════════════════════════╪══════════════╝
     │                  └┬┘                              │
     │                   │                               │
     │<─ ─ ─ ─ ─ ─ ─ ─ ─ │                               │
┌────┴────┐          ┌───┴────┐                      ┌───┴────┐
│UIManager│          │UILayout│                      │children│
└─────────┘          └────────┘                      └────────┘

Size hint support





















Mixin classes are a base class which can be used to apply some specific behaviour. Currently the available Mixins are still under heavy development.


  • UIDraggableMixin

  • UIMouseFilterMixin

  • UIWindowLikeMixin


Constructs are predefined structures of widgets and layouts like a message box.


  • UIMessageBox

  • UIButtonRow

Available Elements


As with most widgets, buttons take x, y, width, and height parameters for their sizing. Buttons specifically have two more parameters - text and multiline.

All button types support styling. And they are text widgets, which means you can use the ui_label attribute to get the UILabel component of the button.

Flat button

Name: FlatButton

A flat button for simple interactions (hover, press, release, click). This button is created with a simple rectangle. Flat buttons can quickly create a nice-looking button. However, depending on your use case, you may want to use a texture button to further customize your look and feel.

Styling options are shown in the table below.




Font size for the button text. Defaults to 12.


Font name or family for the button text. If a tuple is supplied then arcade will attempt to load all of the fonts, prioritizing the first one. Defaults to ("calibri", "arial").


Font color for the button text (foreground). Defaults to white for normal, hover, and disabled states. Defaults to black for pressed state.


Background color of the button. This modifies the color of the rectangle within the button and not the border. Instead of making each of these different colors for each of your buttons, set these towards a common color theme. Defaults to gray for hover and disabled states. Otherwise it is white.


Border color. It is common to only modify this in a focus or hover state. Defaults to white or turquoise for hover.


Width of the border/outline of the button. It is common to make this thicker on a hover or focus state, however an overly thick border will result in your GUI looking old or low-quality. Defaults to 2.

Image/texture button

Name: UITextureButton

An image button. Textures are supplied from arcade.load_texture() for simple interactions (hover, press, release, click). A texture lets you further customize the look of the widget better than styling.

A texture button a few more arguments than a flat button. texture, texture_hovered, and texture_pressed will change the texture displayed on the button respectively. scale will change the scaling or size of the button - it’s similar to the sprite scale.


This widget does have width and height parameters, but they only stretch the texture instead of resizing it with keeping the borders. This feature is currently in-progress.

Texture buttons have fewer styling options when they have a texture compared to flat buttons.




Font size for the button text. Defaults to 12.


Font name or family for the button text. If a tuple is supplied then arcade will attempt to load all of the fonts, prioritizing the first one. Defaults to ("calibri", "arial").


Font color for the button text (foreground). Defaults to white for normal, hover, and disabled states. Defaults to black for pressed state.


Width of the border/outline of the button. It is common to make this thicker on a hover or focus state, however an overly thick border will result in your GUI looking old or low-quality. Defaults to 2.

Text widgets

All text widgets take x and y positioning parameters. They also accept text and multiline options.


Name: UILabel

A label is used to display text as instruction for the user. Multiline text is supported, and what would have been its style options were moved into the parameters.

This widget has no style options whatsoever, and they have been moved into the parameters. bold and italic will set the text to bold or italic. align specifies the justification of the text. Additionally it takes font_name, font_size, and text_color options.

Using the label property accesses the internal Text class.


A text attribute can modify the displayed text. Beware-calling this again and again will give a lot of lag. Use begin_update() and py:meth:~arcade.Text.end_update to speed things up.

Text input field

Name: UIInputText

A text field allows a user to input a basic string. It uses pyglet’s IncrementalTextLayout and its Caret. These are stored in layout and caret properties.

This widget takes width and height properties and uses a rectangle to display a background behind the layout.

A text input field allows the user to move a caret around text to modify it, as well as selecting parts of text to replace or delete it. Motion symbols for a text field are listed in pyglet.window.key module.

Text area

Name: UITextArea

A text area is a scrollable text widget. A user can scroll the mouse to view a rendered text document. This does not support editing text. Think of it as a scrollable label instead of a text field.

width and height allocate a size for the text area. If text does not fit within these dimensions then only part of it will be displayed. Scrolling the mouse will display other sections of the text incrementally. Other parameters include multiline and scroll_speed. See view_y on scroll speed.

Use layout and doc to get the pyglet layout and document for the text area, respectively.

User-interface events

Arcade’s GUI events are fully typed dataclasses, which provide information about an event affecting the UI.

All pyglet window events are converted by the UIManager into UIEvents and passed via dispatch_event() to the on_event() callbacks.

Widget-specific events (such as UIOnClickEvent are dispatched via on_event and are then dispatched as specific event types (like on_click).

A full list of event attributes is shown below.






x, y


dx, dy


dx, dy, button, modifiers


dx, dy


scroll_x, scroll_y


symbol, modifiers














old_value, new_value



  • arcade.gui.UIEvent. Base class for all events.

  • arcade.gui.UIMouseEvent. Base class for mouse-related events.
    • arcade.gui.UIMouseMovementEvent. Mouse motion. This event has an additional pos property that returns a tuple of the x and y coordinates.

    • UIMousePressEvent. Mouse button pressed.

    • UIMouseDragEvent. Mouse pressed and moved (drag).

    • UIMouseReleaseEvent. Mouse button release.

    • UIMouseScrollEvent. Mouse scroll.

  • UITextEvent. Text input from user. This is only used for text fields and is the text as a string that was inputed.

  • UITextMotionEvent. Text motion events. This includes moving the text around with the caret. Examples include using the arrow keys, backspace, delete, or any of the home/end and PgUp/PgDn keys. Holding Control with an arrow key shifts the caret by a entire word or paragraph. Moving the caret via the mouse does not trigger this event.

  • UITextMotionSelectEvent. Text motion events for selection. Holding down the Shift key and pressing arrow keys (Control optional) will select character(s). Additionally, using a Control-A keyboard combination will select all text. Selecting text via the mouse does not trigger this event.

  • UIOnUpdateEvent. This is a callback to the arcade on_update method.

Widget-specific events

Widget events are only dispatched as a pyglet event on a widget itself and are not passed through the widget tree.

  • UIOnClickEvent. Click event of UIInteractiveWidget class. This is triggered on widget press.

  • UIOnChangeEvent. A value of a UIWidget has changed.

  • UIOnActionEvent. An action results from interaction with the UIWidget (mostly used in constructs)

Different event systems

Arcade’s GUI uses different event systems, dependent on the required flow. A game developer should mostly interact with user-interface events, which are dispatched from specific UIWidget`s like an ``on_click` of a button.

In rare cases a developer might implement some widgets themselves or want to modify the existing GUI behavior. In those cases a developer might register own pyglet event types on widgets or overwrite the on_event method. In that case, refer to existing widgets as an example.

Pyglet window events

Pyglet window events are received by UIManager.

You can dispatch them via:

UIWidget.dispatch_event("on_event", UIEvent(...))

Window events are wrapped into subclasses of UIEvent.

Pyglet event dispatcher - UIWidget

Widgets implement pyglet’s EventDispatcher and register an on_event event type.

on_event() contains specific event handling and should not be overwritten without deeper understanding of the consequences.

To add custom event handling, use the decorator syntax to add another listener:


User-interface events

User-interface events are typed representations of events that are passed within the GUI. Widgets might define and dispatch their own subclasses of these events.


Property is an pure-Python implementation of Kivy like Properties. They are used to detect attribute changes of widgets and trigger rendering. They are mostly used within GUI widgets, but are globally available since 3.0.0.