🎨 Creating Widgets
A health bar that's just a gray rectangle gets the job done, but players expect more. Polished UI uses styled buttons with hover effects, progress bars with custom colors and backgrounds, and text with carefully chosen fonts. In this lesson, you'll learn how to style widgets, explore common widget types in depth, and create reusable UI components that maintain consistency across your game.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Apply styling to widgets including colors, fonts, and images
- Configure common widgets for different use cases
- Create buttons with visual states (normal, hovered, pressed)
- Use images and materials in UI elements
- Build reusable widget components
Estimated Time: 50-60 minutes
Prerequisites: Lesson 7.1 (Introduction to UMG)
📑 In This Lesson
Widget Styling and Appearance
Every widget has appearance properties that control how it looks. Understanding these properties lets you transform default widgets into polished, game-ready UI elements that match your art style.
Color and Opacity
Most widgets have color properties that accept both color and alpha (transparency):
Color and Opacity: A single property combining RGB color with alpha. Found on Text, Image, Progress Bar fill, and more. Alpha of 1.0 is fully opaque; 0.0 is fully transparent.
Tint: Multiplies the widget's color. Useful for colorizing images or creating hover effects without changing the base asset.
Background Color: Available on some widgets like Border. Sets the background behind content.
Colors in UMG use Linear Color (not sRGB), which means values can exceed 1.0 for HDR/bloom effects.
Figure: Different color and opacity configurations.
Fonts and Text Styling
Text widgets have extensive styling options:
Font Family: The typeface used. UE5 includes Roboto by default. You can import custom fonts (.ttf, .otf) and create Font assets.
Font Size: Size in points. Larger sizes are crisper; very small sizes may become unreadable.
Font Style: Regular, Bold, Italic, etc. Depends on what styles your font file includes.
Letter Spacing: Space between characters. Positive values spread letters apart.
Line Height: Space between lines of multi-line text.
Justification: Left, Center, Right alignment.
Text Shadow: Adds a shadow behind text for better readability against complex backgrounds.
Importing Custom Fonts
- Drag a .ttf or .otf file into Content Browser
- Unreal creates a Font Face asset
- Right-click → Create Font → name it (e.g., "MyGameFont")
- In the Font asset, add your Font Face to the Default Font Family
- Use this Font asset in Text widget properties
Figure: Text styling variations including size, style, spacing, and shadows.
Images and Materials
Image widgets can display textures, materials, or nothing (for colored rectangles):
Brush: The main property that controls what's displayed. Can be set to:
- Image: A texture asset (PNG, JPG imported into UE)
- Material: A material or material instance for animated/procedural graphics
- None: Displays Tint color only (solid color rectangle)
Draw As: How the image is rendered:
- Box: Stretches to fill (can distort)
- Border: 9-slice scaling—corners stay fixed, edges stretch
- Image: Displays at original size or specified size
- Rounded Box: Adds rounded corners
9-Slice (Border mode): Essential for scalable UI elements like buttons and panels. Define margins that don't stretch, allowing the middle to scale while corners remain crisp.
Figure: Different Draw As modes for Image widgets.
Padding and Margins
Spacing is controlled through Slot properties and widget-specific padding:
Padding: Space inside a widget, between its edge and its content. Available on panels and some widgets like Button.
Margin: Space outside a widget, between it and siblings. Set in the Slot section of Details when a widget is inside a panel.
Both use four values: Left, Top, Right, Bottom. In many cases you can use "uniform" mode to set all four at once.
💡 Padding vs. Margin
Think of padding as "breathing room inside" and margin as "personal space outside." A button with padding has space between its border and its text. A button with margin has space between itself and neighboring buttons.
Render Transforms
Every widget has Render Transform properties for visual adjustments without affecting layout:
- Translation: Move the widget visually (doesn't affect layout/hit detection)
- Scale: Resize the widget visually
- Shear: Skew the widget
- Angle: Rotate the widget
- Pivot: Point around which rotation and scaling occur
Render transforms are great for animations and effects but remember: they're visual only. The widget's actual bounds don't change, so hit detection may not match what's displayed.
Common Widgets Deep Dive
Let's explore the most frequently used widgets in detail, including their key properties and common use cases.
Button
Buttons are the primary interactive element in UI. They respond to clicks/taps and have visual states for feedback.
Button Structure
A Button widget is actually a container—it can hold child widgets. The typical structure is:
Button
└── Text (or Image, or both)
The button provides the interactivity; the child provides the visual content.
Button States
Buttons have visual styles for different states:
- Normal: Default appearance
- Hovered: Mouse is over the button
- Pressed: Button is being clicked
- Disabled: Button is not interactive (Is Enabled = false)
Each state can have its own image/color in the Style section of Details.
Figure: Button states provide visual feedback for interaction.
Button Events
Buttons fire several events you can bind to:
- On Clicked: Fires when button is pressed and released (most common)
- On Pressed: Fires immediately when button is pressed down
- On Released: Fires when button is released
- On Hovered: Fires when mouse enters button area
- On Unhovered: Fires when mouse leaves button area
To bind an event, select the button and scroll to the Events section in Details. Click the + next to the event to create a handler in the Graph.
Text Block
Text Block displays text—static or dynamic. It's the workhorse of UI information display.
Key Properties
- Text: The content to display. Can be set directly or bound to a variable/function
- Font: Family, size, and style settings
- Color and Opacity: Text color with transparency
- Justification: Left, Center, Right alignment
- Wrapping Policy: How text wraps when it exceeds available width
- Auto Wrap Text: Automatically wrap at widget boundaries
Rich Text
For text with multiple styles (bold words, colored phrases), use the Rich Text Block widget instead. It supports markup like:
<Bold>Important</> text with <Red>color</>
Rich Text requires a Data Table defining your styles.
Image
Image widgets display textures or materials. They're used for icons, backgrounds, character portraits, and decorative elements.
Key Properties
- Brush → Image: The texture to display
- Brush → Draw As: Box, Border (9-slice), Image, or Rounded Box
- Brush → Tint: Color multiplied with image
- Brush → Image Size: Override the displayed size
- Color and Opacity: Overall color/transparency of the image
Using Materials
For animated or procedural images, use a Material:
- Create a Material with User Interface material domain
- Build your material (animated patterns, effects)
- In Image widget, set Brush → Image to your Material
This enables animated backgrounds, procedural patterns, and dynamic effects impossible with static textures.
Progress Bar
Progress bars visualize a value between 0 and 1. Perfect for health, experience, loading, and timers.
Key Properties
- Percent: Fill amount from 0.0 (empty) to 1.0 (full)
- Fill Type: Direction of fill (Left to Right, Right to Left, etc.)
- Is Marquee: Animated "loading" style when true
- Style → Background Image: The unfilled portion appearance
- Style → Fill Image: The filled portion appearance
- Fill Color and Opacity: Color of the fill
Figure: Progress bars for different purposes using various styles.
Slider
Sliders let users select a value within a range—perfect for volume controls, brightness settings, and similar options.
Key Properties
- Value: Current position (0.0 to 1.0 by default)
- Min Value / Max Value: Range endpoints (can be customized)
- Step Size: Increment size (0 for continuous)
- Orientation: Horizontal or Vertical
- Style: Appearance of bar and handle
Slider Events
- On Value Changed: Fires whenever value changes (continuously while dragging)
- On Mouse Capture Begin: Fires when user starts dragging
- On Mouse Capture End: Fires when user releases
Check Box
Check boxes toggle boolean settings—enable/disable features, agree to terms, select options.
Key Properties
- Is Checked: Current checked state
- Checked State: Unchecked, Checked, or Undetermined (for tri-state)
- Style: Appearance for each state
Check Box Events
- On Check State Changed: Fires when state changes, provides new state as parameter
Editable Text / Text Box
For user text input—player names, chat messages, search fields.
Key Properties
- Text: Current content
- Hint Text: Placeholder shown when empty
- Is Read Only: Whether user can edit
- Is Password: Obscure input with dots
Text Input Events
- On Text Changed: Fires on every keystroke
- On Text Committed: Fires when Enter is pressed or focus is lost
⚠️ Mobile Keyboard
On mobile devices, focusing a text input automatically shows the on-screen keyboard. Consider the layout—your text field shouldn't be hidden behind the keyboard. Also consider what keyboard type you need (default, numeric, email).
Widget Composition and Reusability
Professional UI isn't built by styling every element individually—that leads to inconsistency and maintenance nightmares. Instead, you create reusable widget components that can be combined to build complex interfaces. One styled button definition used everywhere; change it once, it updates everywhere.
User Widgets (Custom Widget Components)
A User Widget is a Widget Blueprint that can be used as a component inside other Widget Blueprints. Create a styled button once, then drop it into any menu or HUD.
Why User Widgets?
- Consistency: Same look everywhere without manual copying
- Maintainability: Update one widget, all instances update
- Encapsulation: Internal complexity hidden behind simple interface
- Reusability: Use across multiple screens and even projects
Creating a User Widget
- Create a Widget Blueprint as normal (right-click → User Interface → Widget Blueprint)
- Design your component (e.g., a styled button with icon and text)
- Add variables that should be configurable (button text, icon, colors)
- Mark variables as Instance Editable and Expose on Spawn
- Use this widget inside other Widget Blueprints by dragging from Palette → User Created
Figure: A User Widget defined once can be instanced in multiple locations. Updating the definition updates all instances.
Exposing Variables
For a User Widget to be configurable, expose variables that other widgets can set:
- Create a variable in your User Widget (e.g.,
ButtonTextof type Text) - Select the variable and in Details:
- Check Instance Editable — allows setting per-instance in parent widget
- Check Expose on Spawn — allows setting when created dynamically
- Use the variable in your widget's design (bind text to it, etc.)
When you place this User Widget in another Widget Blueprint, the exposed variables appear in the Details panel, allowing you to configure each instance differently.
Event Dispatchers for Communication
User Widgets need to communicate events to their parents—"button was clicked," "slider value changed." Event Dispatchers enable this.
Creating an Event Dispatcher:
- In your User Widget, open the My Blueprint panel
- Under Event Dispatchers, click + to add one
- Name it descriptively (e.g.,
OnButtonClicked) - Optionally add parameters (the data to pass when fired)
Calling the Dispatcher:
- When the internal event happens (button clicked), call the dispatcher
- Drag the dispatcher into the graph and select "Call"
Binding in Parent Widget:
- In the parent widget, get reference to your User Widget instance
- Drag from it and search for "Bind Event to [DispatcherName]"
- Create a custom event to handle the callback
flowchart LR
subgraph UserWidget["WBP_StyledButton"]
B["Button Clicked"] --> C["Call OnButtonClicked"]
end
subgraph ParentWidget["WBP_MainMenu"]
D["Bind to OnButtonClicked"] --> E["Handle Click"]
E --> F["Start Game / Open Settings / etc."]
end
C -.->|"Event Dispatcher"| D
style B fill:#c62828,color:#fff
style C fill:#667eea,color:#fff
style D fill:#667eea,color:#fff
style F fill:#4CAF50,color:#fff
Figure: Event Dispatchers let child widgets communicate with parents.
Named Slots
Sometimes you want a User Widget that accepts arbitrary content—like a panel frame that can contain anything. Named Slots enable this.
- In your User Widget Designer, add a Named Slot widget where content should go
- Give it a descriptive name (e.g., "ContentSlot")
- When using this widget in a parent, drag child widgets into the slot
Named Slots are perfect for:
- Styled containers (fancy borders around any content)
- Card layouts (title bar + content area)
- Scroll views with custom frames
Widget Switching and Visibility
Complex UIs often show/hide different panels. Use the Widget Switcher panel:
- Add a Widget Switcher to your layout
- Add multiple child widgets (each is a "page")
- Only one child is visible at a time
- Call
Set Active Widget IndexorSet Active Widgetto switch
This is more efficient than showing/hiding multiple overlapping widgets—only the active widget processes input and ticks.
Figure: Widget Switcher shows one child at a time, perfect for tabbed interfaces.
Organizing Your Widgets
As your UI grows, organization becomes crucial:
Folder Structure:
Content/
└── UI/
├── Components/ (Reusable User Widgets)
│ ├── WBP_StyledButton
│ ├── WBP_HealthBar
│ └── WBP_ItemSlot
├── Screens/ (Full-screen widgets)
│ ├── WBP_MainMenu
│ ├── WBP_PauseMenu
│ └── WBP_Inventory
├── HUD/ (In-game overlays)
│ ├── WBP_PlayerHUD
│ └── WBP_DamageIndicator
└── Common/ (Shared assets)
├── Fonts/
├── Icons/
└── Materials/
Naming Conventions:
WBP_prefix for all Widget Blueprints- Descriptive names:
WBP_MainMenuButtonnotWBP_Button1 - Group related widgets:
WBP_Inventory_Slot,WBP_Inventory_Panel
✅ Component Checklist
When creating a reusable User Widget:
- Expose configuration variables (text, colors, icons)
- Create Event Dispatchers for important events
- Document what the widget does and how to use it
- Test with different configurations before using widely
- Keep it focused—one component, one purpose
Hands-On: Create a Styled Menu Button
Let's create a reusable button component with custom styling, hover effects, and an Event Dispatcher. This button can then be used throughout your game's menus.
🎯 Exercise Goal
Create a styled menu button User Widget with: customizable text, hover color change effect, click sound, and an Event Dispatcher for click handling. Use it in a simple main menu.
Step 1: Create the Button Widget
- Right-click in Content Browser → User Interface → Widget Blueprint
- Name it
WBP_MenuButton - Open it in the Widget Editor
Step 2: Design the Button Layout
- From Palette, drag a Button into the canvas
- Select the button, in Details:
- Set Size X: 300
- Set Size Y: 60
- Drag a Text widget inside the Button (as child)
- Rename the Text to
ButtonText - In Text Details:
- Set Text: "Button" (placeholder)
- Set Font Size: 24
- Set Justification: Center
- Check Is Variable (so we can access it in Graph)
Step 3: Style the Button
Select the Button widget and expand the Style section in Details:
Normal State:
- Under Style → Normal, click the dropdown and select "None" for Image
- Set Tint to your primary color (e.g., #667EEA - a nice purple-blue)
Hovered State:
- Under Style → Hovered, set Image to "None"
- Set Tint to a lighter version (e.g., #8B9CF9)
Pressed State:
- Under Style → Pressed, set Image to "None"
- Set Tint to a darker version (e.g., #5560D4)
Figure: Three button states with color variations for visual feedback.
Step 4: Create Exposed Variables
Switch to the Graph view and create variables:
- In My Blueprint panel, under Variables, click +
- Create
LabelText(Type: Text, Default: "Button") - Select it, in Details:
- Check Instance Editable
- Check Expose on Spawn
Step 5: Bind Text to Variable
- Switch back to Designer view
- Select the ButtonText widget
- In Details, find Text property
- Click the Bind dropdown next to it
- Select Create Binding
- This creates a function—inside it:
- Get
LabelTextvariable - Connect to the Return Value
- Get
Now the button text will display whatever LabelText is set to!
Step 6: Create Event Dispatcher
- In Graph view, find Event Dispatchers in My Blueprint panel
- Click + to add one
- Name it
OnClicked
Step 7: Handle Button Click
- Select the Button widget (in Designer or Hierarchy)
- In Details, scroll to Events section
- Click + next to
On Clicked - This adds an event node to your Graph
- From this event:
- Drag
OnClicked(Event Dispatcher) into graph - Select Call
- Connect the execution wire
- Drag
Figure: Button click calls the Event Dispatcher, which parents can bind to.
Step 8: Compile and Save
- Click Compile
- Click Save
Step 9: Create a Main Menu Using the Button
- Create a new Widget Blueprint:
WBP_MainMenu - Add a Canvas Panel as root
- Add a Vertical Box (centered using anchor)
- In Palette, find User Created → WBP_MenuButton
- Drag three instances into the Vertical Box
- Select each and set
LabelTextin Details:- First: "Play Game"
- Second: "Options"
- Third: "Quit"
Step 10: Bind Event Dispatchers
- Switch to Graph view in WBP_MainMenu
- For each button instance:
- Drag the button variable into graph
- Drag from it and search "Bind Event to On Clicked"
- Create custom event (e.g., "OnPlayClicked", "OnOptionsClicked", "OnQuitClicked")
- Implement each handler:
- Play: Open Level or Print String "Starting Game"
- Options: Print String "Opening Options"
- Quit: Quit Game node
Step 11: Test
- Create a test level or use existing
- In Level Blueprint or Player Controller, add WBP_MainMenu to viewport on BeginPlay
- Set Input Mode UI Only
- Set Show Mouse Cursor = True
- Play and test your menu!
✅ Exercise Complete!
You've created a reusable styled button with:
- Custom visual styling with state colors
- Exposed variables for configuration
- Event Dispatcher for parent communication
- Text binding to display different labels
This same pattern works for any reusable UI component—inventory slots, stat displays, notification toasts, and more!
Bonus Challenges
- Add Icon: Add an optional Image widget next to text, expose Icon texture variable
- Hover Sound: Play a sound on the On Hovered event
- Click Sound: Play a click sound before calling the dispatcher
- Scale Animation: Use Render Transform to slightly scale up on hover
- Disabled State: Add logic to show disabled appearance when Is Enabled is false
Summary
In this lesson, you've learned how to move beyond default widget appearances to create polished, professional UI. From styling individual elements to building reusable components, you now have the skills to create consistent, maintainable user interfaces.
Key Concepts
Widget Styling: Every widget has appearance properties—colors with alpha, fonts with size and style, images with draw modes. Use these to match your game's visual identity. 9-slice (Border mode) is essential for scalable UI elements.
Text Styling: Font family, size, style, spacing, shadows, and justification all contribute to readable, attractive text. Import custom fonts to maintain brand consistency.
Button States: Buttons have Normal, Hovered, Pressed, and Disabled states. Each can have unique styling to provide clear visual feedback during interaction.
Common Widgets: Text Block for displaying information, Image for graphics, Progress Bar for values, Slider for user input ranges, Check Box for toggles, and Text Box for text input. Each has specific properties and events.
User Widgets: Reusable components created as Widget Blueprints. Define once, use everywhere. Update the definition and all instances update automatically.
Exposed Variables: Mark variables as Instance Editable and Expose on Spawn to allow configuration per-instance. Bind widget properties to these variables.
Event Dispatchers: Enable child widgets to communicate events to parents. The child calls the dispatcher; parents bind handlers to respond.
Widget Switcher: Efficiently shows one child widget at a time, perfect for tabbed interfaces and multi-page menus.
Styling Quick Reference
| Property | Widgets | Purpose |
|---|---|---|
| Color and Opacity | Most widgets | Base color with transparency |
| Tint | Image, Button styles | Color multiplier for variations |
| Font | Text Block, Editable Text | Family, size, style |
| Draw As | Image | Box, Border (9-slice), Image, Rounded |
| Padding | Panels, Button | Space inside widget |
| Render Transform | All widgets | Visual-only position/scale/rotation |
Widget Events Quick Reference
| Widget | Key Events | Use Case |
|---|---|---|
| Button | On Clicked, On Hovered | Menu actions, confirmations |
| Slider | On Value Changed | Volume, brightness settings |
| Check Box | On Check State Changed | Toggle options |
| Text Box | On Text Committed | Player name, chat input |
Best Practices
- Create reusable components: Any UI element used more than twice should be a User Widget
- Use Event Dispatchers: Keep widget logic encapsulated; communicate through dispatchers
- Expose only necessary variables: Don't expose everything—just what needs configuration
- Name widgets descriptively: ButtonText, HealthBar, not TextBlock_3
- Use consistent styling: Define colors, fonts, and sizes once and reuse
- Test button states: Verify all states look good and provide clear feedback
- Use 9-slice for scalable elements: Buttons, panels, and frames should scale without distortion
- Organize your UI folder: Separate Components, Screens, HUD, and Common assets
Figure: The workflow for creating professional, reusable UI components.
What's Next?
Now that you can create and style widgets, the next lesson focuses on HUD Elements. You'll learn how to create in-game UI that updates in real-time—health bars that reflect actual player health, ammo counters that decrease when shooting, and objective markers that point to goals. This is where UI meets gameplay!
Knowledge Check
Question 1
What is the "Draw As: Border" mode used for in Image widgets?
Correct answer: B — Border mode (9-slice) divides the image into 9 sections. The corners remain fixed size, while edges and center stretch. This is essential for scalable UI elements like buttons and panels that need to resize without distorting their borders.
Question 2
Which button state is active when the mouse is over the button but not clicking?
Correct answer: B — Hovered state activates when the mouse cursor is over the button but the user hasn't clicked yet. This provides visual feedback that the button is interactive. Normal is the default state, Pressed is during click.
Question 3
What must you enable on a variable for it to be configurable per-instance when the User Widget is placed in another widget?
Correct answer: C — Instance Editable allows each instance of a User Widget to have different values for that variable. Combined with "Expose on Spawn," it enables full configuration both in the editor and when creating widgets dynamically.
Question 4
How does a User Widget communicate events (like button clicks) to its parent widget?
Correct answer: B — Event Dispatchers are the proper way for child widgets to communicate with parents. The child widget calls the dispatcher when an event occurs; parent widgets bind handlers to respond. This maintains proper encapsulation.
Question 5
What widget is best for showing one of several pages/panels at a time (like tabs)?
Correct answer: C — Widget Switcher holds multiple child widgets but only displays one at a time. Use Set Active Widget Index to switch between them. This is more efficient than showing/hiding overlapping widgets.
Question 6
What is the difference between Padding and Margin?
Correct answer: B — Padding is the space inside a widget, between its border and its content. Margin is the space outside a widget, between it and neighboring widgets. Think of padding as "breathing room inside" and margin as "personal space outside."
Question 7
When should you create a User Widget instead of manually styling elements?
Correct answer: B — Any UI element used more than once or twice should be a User Widget. This ensures consistency, makes maintenance easier (update once, changes everywhere), and reduces the chance of styling inconsistencies across your UI.