A lightweight, Arduino-compatible UI widget library built on M5GFX for the M5Stack Tab5's 5-inch 1280×720 IPS capacitive touchscreen. Supports both landscape (1280×720) and portrait (720×1280) orientations.
| Widget | Description |
|---|---|
| UILabel | Static/dynamic text with alignment, color, and background options |
| UIButton | Rounded-rect button with press feedback and customizable colors |
| UIIconButton | Button with PROGMEM PNG icon (32×32) and text fallback, same styling as UIButton |
| UISlider | Horizontal slider with draggable thumb, configurable min/max range, and onChange callback |
| UITitleBar | Full-width top bar with center title, optional left/right touch zones |
| UIStatusBar | Full-width bottom bar with left/center/right text |
| UITextRow | Key-value row with label on left, value on right, and dividers |
| UIIconSquare | Colored square icon with optional character overlay |
| UIIconCircle | Colored circle icon with circular hit-testing |
| UIMenu | Modal popup menu with selectable items, separators, and auto-dismiss |
| UITextInput | Single-line text input field with placeholder and focus highlight |
| UIKeyboard | Full-screen modal QWERTY touch keyboard with Shift, Symbols, and Enter |
| UIList | Scrollable list with touch-drag scrolling, item selection, and scrollbar |
| UITabView | Multi-page tabbed container with configurable top/bottom tab bar |
| UIInfoPopup | Auto-sized modal info popup with title, message, and OK button |
| UIConfirmPopup | Auto-sized modal confirm popup with title, message, and Yes/No buttons |
| UIScrollText | Scrollable text display with basic Markdown rendering (headings, bold, italic, code, bullets, rules) |
| UICheckbox | Toggleable checkbox with label, checked state, and touch callbacks |
| UIRadioButton | Selectable radio button with label, managed by UIRadioGroup for mutual exclusion |
| UIDropdown | Compact dropdown selector with scrollable list overlay, icons, and all UIList features |
| UIColumnList | Multi-column list with sortable headers, per-cell text/color/icon, scrolling, and selection |
| UIScrollTextPopup | Large modal popup with scrollable Markdown text, Close button, and tap-outside dismiss |
| UITextArea | Multi-line text input with word wrapping, touch scrolling, and tap-to-place cursor |
| UIManager | Registers elements, dispatches touch events, manages dirty redraws |
Every widget supports two callbacks:
element.setOnTouch([](TouchEvent e) {
// Finger touched down on this element
});
element.setOnTouchRelease([](TouchEvent e) {
// Finger lifted from this element
});The UIManager::update() method handles all touch detection, hit-testing (including circular hit-test for UIIconCircle), and dirty-region redraws automatically.
Ten widgets use sprite-buffered (double-buffered) rendering via a shared M5Canvas allocated in PSRAM for flicker-free display updates. See the Rendering wiki page for details and render mode configuration.
-
Copy the entire
Tab5UIfolder into your Arduino libraries directory:- macOS:
~/Documents/Arduino/libraries/Tab5UI/ - Windows:
Documents\Arduino\libraries\Tab5UI\ - Linux:
~/Arduino/libraries/Tab5UI/
- macOS:
-
Install the M5GFX library via the Arduino Library Manager:
- Sketch → Include Library → Manage Libraries → search "M5GFX"
-
Select board M5Stack Tab5 (or the appropriate ESP32-P4 board).
Add to platformio.ini:
[env:tab5]
platform = espressif32
board = m5stack-tab5
framework = arduino
lib_deps =
m5stack/M5GFX
Tab5UI#include <M5GFX.h>
#include <Tab5UI.h>
M5GFX display;
UIManager ui(display);
UITitleBar titleBar("My App");
UIStatusBar statusBar("Ready");
UIButton btn(50, 100, 200, 52, "Press Me");
void setup() {
display.init();
display.setRotation(1); // Landscape (use 0 for portrait)
Tab5UI::init(display); // Must be called after init + rotation
ui.setBrightness(128);
display.setFont(&fonts::DejaVu18);
btn.setOnTouchRelease([](TouchEvent e) {
statusBar.setText("Button pressed!");
});
ui.setBackground(Tab5Theme::BG_DARK);
ui.clearScreen();
ui.addElement(&titleBar);
ui.addElement(&btn);
ui.addElement(&statusBar);
ui.setContentArea(TAB5_TITLE_H, Tab5UI::screenH() - TAB5_STATUS_H);
ui.drawAll();
ui.setSleepTimeout(5); // Screen off after 5 min idle
ui.setLightSleep(true); // Low-power idle with touch-to-wake
}
void loop() {
ui.update();
yield();
}Tab5UI works in both landscape (1280×720, rotation 1) and portrait (720×1280, rotation 0) orientations.
Call Tab5UI::init(display) once in setup() after display.init() and display.setRotation():
void setup() {
display.init();
display.setRotation(0); // 0 = portrait, 1 = landscape
Tab5UI::init(display); // Captures runtime screen dimensions
// ...
}| Widget | Adaptation |
|---|---|
| UITitleBar | Stretches to screen width |
| UIStatusBar | Stretches to screen width, repositions to screen bottom |
| UIKeyboard | Repositions to screen bottom, keys scale to fit width |
| UIInfoPopup | Auto-sizes and centers within actual screen bounds |
| UIConfirmPopup | Auto-sizes and centers within actual screen bounds |
| UIScrollTextPopup | Fills between title bar and status bar in any orientation |
| UIDropdown | Overflow detection uses actual screen height |
| UIManager | Content area bottom defaults to actual screen height |
int16_t w = Tab5UI::screenW(); // Actual screen width (720 or 1280)
int16_t h = Tab5UI::screenH(); // Actual screen height (1280 or 720)Use these instead of the compile-time TAB5_SCREEN_W / TAB5_SCREEN_H macros when you need values that match the current orientation.
Since widget objects are constructed globally (before setup()), use compile-time defaults or placeholder values in constructors, then call setPosition() / setSize() in setup() after Tab5UI::init(). See the WiFi Scanner demo for a complete portrait example.
Full API documentation, widget references, and screenshots are available on the Tab5UI Wiki:
| Page | Contents |
|---|---|
| Getting Started | Installation, quick start, orientation support |
| API Reference | Namespace, screen constants, theme colors, UIElement base class |
| Widgets – Basic | UILabel, UIButton, UIIconButton, UISlider, UITitleBar, UIStatusBar, UITextRow, UIIconSquare, UIIconCircle |
| Widgets – Input | UITextInput, UIKeyboard, UITextArea |
| Widgets – Lists | UIList, UIDropdown, UIColumnList |
| Widgets – Containers & Popups | UITabView, UIMenu, UIInfoPopup, UIConfirmPopup, UIScrollText |
| Widgets – Selection | UICheckbox, UIRadioButton / UIRadioGroup |
| UIManager | Element management, touch dispatch, screen sleep |
| Rendering | Sprite buffering, render modes |
| Screenshots | All demo screenshots |
| Tips & Best Practices | Common patterns and memory considerations |
Tab5UI/
├── Tab5UI.h # Header — all class declarations
├── Tab5UI.cpp # Implementation
├── library.properties # Arduino IDE metadata
├── library.json # PlatformIO metadata
├── README.md # This file
├── CHANGELOG.md # Version history
├── LICENSE # GNU GPL v3
├── icons/ # 32×32 PROGMEM PNG icon headers
│ ├── README.md # Icon attribution & usage
│ ├── LICENSE # Apache 2.0 (IconPark)
│ ├── icon_home.h # Example: home icon
│ ├── icon_search.h # Example: search icon
│ └── ... (55 icons total) # See icons/README.md for full list
├── screenshots/ # Demo screenshots
│ ├── screenshot1_initial.png
│ ├── screenshot2_menu.png
│ ├── screenshot3_keyboard.png
│ ├── screenshot4_popup.png
│ ├── screenshot5_list.png
│ ├── screenshot6_tab_controls.png
│ ├── screenshot7_tab_list.png
│ ├── screenshot8_confirm_popup.png
│ ├── screenshot9_tab_text.png
│ ├── screenshot10_column_list.png
│ └── screenshot11_scroll_text_popup.png
└── examples/
├── Tab5UI_Demo/
│ └── Tab5UI_Demo.ino # Full demo sketch (landscape)
├── Tab5UI_List_Demo/
│ └── Tab5UI_List_Demo.ino # List widget demo (landscape)
├── Tab5UI_Tab_Demo/
│ └── Tab5UI_Tab_Demo.ino # Tab view demo (landscape)
├── Tab5UI_WiFi_Demo/
│ └── Tab5UI_WiFi_Demo.ino # WiFi scanner demo (portrait)
├── Tab5UI_TextArea_Demo/
│ └── Tab5UI_TextArea_Demo.ino # Multi-line text input demo (portrait)
└── Tab5UI_ColumnList_Demo/
└── Tab5UI_ColumnList_Demo.ino # Column list demo (landscape)
└── Tab5UI_ScrollTextPopup_Demo/
└── Tab5UI_ScrollTextPopup_Demo.ino # Scroll text popup demo (landscape)
A few highlights — see the Screenshots wiki page for all demo screenshots.
![]() |
![]() |
![]() |
![]() |
![]() |
This project is licensed under the GNU General Public License v3.0.
The icons included in the icons/ directory are from IconPark by ByteDance, Inc., licensed under the Apache License 2.0. The original SVG icons were converted to 32×32 pixel PNG images and embedded as PROGMEM C byte arrays for use on embedded platforms.




