Skip to main content

🎨 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.

Color and Opacity Examples Button Alpha: 1.0 Fully Opaque Button Alpha: 0.5 Semi-Transparent Button Tint: Red Color Multiplied Button Color > 1.0 HDR Bloom

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

  1. Drag a .ttf or .otf file into Content Browser
  2. Unreal creates a Font Face asset
  3. Right-click → Create Font → name it (e.g., "MyGameFont")
  4. In the Font asset, add your Font Face to the Default Font Family
  5. Use this Font asset in Text widget properties
Text Styling Options Size 12 Size 16 Size 24 Font Size Regular Bold Italic Bold Italic Font Style NORMAL SPACED WIDE Letter Spacing No Shadow Shadow Shadow Soft Shadow Soft Shadow Text Shadow

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.

Image Draw Modes Box (Stretch) Stretches to fill May distort image Border (9-Slice) Corners fixed Edges stretch, corners don't Image Original Original or specified size Rounded Box Procedural corners Adjustable corner radius

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.

Button Visual States Play Game Normal Default state Play Game Hovered Mouse over Play Game Pressed Being clicked Play Game Disabled Not interactive

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:

  1. Create a Material with User Interface material domain
  2. Build your material (animated patterns, effects)
  3. 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
Progress Bar Variations Health Bar 67% HP Experience Bar Level 5 (70%) Loading Bar 40% Timer (Countdown) 30% time remaining Radial (Custom) 75% Requires custom material Segmented (Custom) 3/5 health segments

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

  1. Create a Widget Blueprint as normal (right-click → User Interface → Widget Blueprint)
  2. Design your component (e.g., a styled button with icon and text)
  3. Add variables that should be configurable (button text, icon, colors)
  4. Mark variables as Instance Editable and Expose on Spawn
  5. Use this widget inside other Widget Blueprints by dragging from Palette → User Created
User Widget: Define Once, Use Everywhere WBP_StyledButton (User Widget Definition) {ButtonText} Exposed Variables: ButtonText, IconTexture, OnClick Play Game Main Menu Settings Pause Menu Confirm Dialog Popup Update Definition → All Instances Update! Play Game Settings Confirm

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:

  1. Create a variable in your User Widget (e.g., ButtonText of type Text)
  2. 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
  3. 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:

  1. In your User Widget, open the My Blueprint panel
  2. Under Event Dispatchers, click + to add one
  3. Name it descriptively (e.g., OnButtonClicked)
  4. Optionally add parameters (the data to pass when fired)

Calling the Dispatcher:

  1. When the internal event happens (button clicked), call the dispatcher
  2. Drag the dispatcher into the graph and select "Call"

Binding in Parent Widget:

  1. In the parent widget, get reference to your User Widget instance
  2. Drag from it and search for "Bind Event to [DispatcherName]"
  3. 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.

  1. In your User Widget Designer, add a Named Slot widget where content should go
  2. Give it a descriptive name (e.g., "ContentSlot")
  3. 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:

  1. Add a Widget Switcher to your layout
  2. Add multiple child widgets (each is a "page")
  3. Only one child is visible at a time
  4. Call Set Active Widget Index or Set Active Widget to switch

This is more efficient than showing/hiding multiple overlapping widgets—only the active widget processes input and ticks.

Widget Switcher: Multi-Page UI Inventory Skills Map Quests Widget Switcher ... Inventory Content ... Active Index: 0 Only active child widget is visible and receives input • Switch with Set Active Widget Index

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_MainMenuButton not WBP_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

  1. Right-click in Content Browser → User Interface → Widget Blueprint
  2. Name it WBP_MenuButton
  3. Open it in the Widget Editor

Step 2: Design the Button Layout

  1. From Palette, drag a Button into the canvas
  2. Select the button, in Details:
    • Set Size X: 300
    • Set Size Y: 60
  3. Drag a Text widget inside the Button (as child)
  4. Rename the Text to ButtonText
  5. 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:

  1. Under Style → Normal, click the dropdown and select "None" for Image
  2. Set Tint to your primary color (e.g., #667EEA - a nice purple-blue)

Hovered State:

  1. Under Style → Hovered, set Image to "None"
  2. Set Tint to a lighter version (e.g., #8B9CF9)

Pressed State:

  1. Under Style → Pressed, set Image to "None"
  2. Set Tint to a darker version (e.g., #5560D4)
WBP_MenuButton Styling Play Game Normal #667EEA Play Game Hovered #8B9CF9 (lighter) Play Game Pressed #5560D4 (darker) Widget Structure Button → Text (ButtonText)

Figure: Three button states with color variations for visual feedback.

Step 4: Create Exposed Variables

Switch to the Graph view and create variables:

  1. In My Blueprint panel, under Variables, click +
  2. Create LabelText (Type: Text, Default: "Button")
  3. Select it, in Details:
    • Check Instance Editable
    • Check Expose on Spawn

Step 5: Bind Text to Variable

  1. Switch back to Designer view
  2. Select the ButtonText widget
  3. In Details, find Text property
  4. Click the Bind dropdown next to it
  5. Select Create Binding
  6. This creates a function—inside it:
    • Get LabelText variable
    • Connect to the Return Value

Now the button text will display whatever LabelText is set to!

Step 6: Create Event Dispatcher

  1. In Graph view, find Event Dispatchers in My Blueprint panel
  2. Click + to add one
  3. Name it OnClicked

Step 7: Handle Button Click

  1. Select the Button widget (in Designer or Hierarchy)
  2. In Details, scroll to Events section
  3. Click + next to On Clicked
  4. This adds an event node to your Graph
  5. From this event:
    • Drag OnClicked (Event Dispatcher) into graph
    • Select Call
    • Connect the execution wire
Button Click → Event Dispatcher On Clicked (Button Event) Call OnClicked (Event Dispatcher) Parent Widget Handles Event Button internal click triggers dispatcher → Parent widget receives and handles

Figure: Button click calls the Event Dispatcher, which parents can bind to.

Step 8: Compile and Save

  1. Click Compile
  2. Click Save

Step 9: Create a Main Menu Using the Button

  1. Create a new Widget Blueprint: WBP_MainMenu
  2. Add a Canvas Panel as root
  3. Add a Vertical Box (centered using anchor)
  4. In Palette, find User Created → WBP_MenuButton
  5. Drag three instances into the Vertical Box
  6. Select each and set LabelText in Details:
    • First: "Play Game"
    • Second: "Options"
    • Third: "Quit"

Step 10: Bind Event Dispatchers

  1. Switch to Graph view in WBP_MainMenu
  2. 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")
  3. Implement each handler:
    • Play: Open Level or Print String "Starting Game"
    • Options: Print String "Opening Options"
    • Quit: Quit Game node

Step 11: Test

  1. Create a test level or use existing
  2. In Level Blueprint or Player Controller, add WBP_MainMenu to viewport on BeginPlay
  3. Set Input Mode UI Only
  4. Set Show Mouse Cursor = True
  5. 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

  1. Add Icon: Add an optional Image widget next to text, expose Icon texture variable
  2. Hover Sound: Play a sound on the On Hovered event
  3. Click Sound: Play a click sound before calling the dispatcher
  4. Scale Animation: Use Render Transform to slightly scale up on hover
  5. 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
Widget Creation Workflow 1. Style Colors, fonts, images, states 2. Expose Variables for configuration 3. Events Dispatchers for communication 4. Reuse Use across all menus/HUDs Consistent, Maintainable UI Change once → Updates everywhere

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.