Skip to main content
The UiBuilder is the central interface for creating custom UI in Dalamud plugins. It provides access to the ImGui rendering system, font management, and event-driven drawing.

Getting Started

Access the UiBuilder through your plugin’s DalamudPluginInterface:
public class MyPlugin : IDalamudPlugin
{
    private DalamudPluginInterface PluginInterface { get; init; }
    
    public MyPlugin(DalamudPluginInterface pluginInterface)
    {
        this.PluginInterface = pluginInterface;
        
        // Subscribe to the Draw event
        this.PluginInterface.UiBuilder.Draw += DrawUI;
        this.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
    }
    
    private void DrawUI()
    {
        ImGui.Begin("My Window");
        ImGui.Text("Hello, world!");
        ImGui.End();
    }
    
    public void Dispose()
    {
        this.PluginInterface.UiBuilder.Draw -= DrawUI;
        this.PluginInterface.UiBuilder.OpenConfigUi -= DrawConfigUI;
    }
}

Core Events

Draw Event

The Draw event is called every frame when Dalamud is ready to render plugin UI. This is where you should place all your ImGui rendering code.
public event Action? Draw;
The Draw event is called from the main thread during the game’s rendering pipeline. All ImGui calls must be made within this event or its callbacks.

OpenConfigUi Event

Triggered when the user requests to open your plugin’s configuration interface (e.g., via /xlplugins settings button):
public event Action? OpenConfigUi;
Example:
this.PluginInterface.UiBuilder.OpenConfigUi += () =>
{
    this.configWindow.IsOpen = true;
};

OpenMainUi Event

Triggered when the user requests to open your plugin’s main interface:
public event Action? OpenMainUi;

ShowUi / HideUi Events

These events fire when plugin UI should be shown or hidden based on game state:
public event Action? ShowUi;
public event Action? HideUi;
Example: Respecting UI visibility
private bool isUiVisible = true;

public MyPlugin(DalamudPluginInterface pluginInterface)
{
    pluginInterface.UiBuilder.ShowUi += () => this.isUiVisible = true;
    pluginInterface.UiBuilder.HideUi += () => this.isUiVisible = false;
}

private void DrawUI()
{
    if (!this.isUiVisible) return;
    
    // Draw your UI
}

Automatic UI Hiding

The UiBuilder provides properties to control automatic UI hiding behavior:
// Disable automatic hiding when game UI is hidden
public bool DisableAutomaticUiHide { get; set; }

// Disable hiding when user toggles UI (Scroll Lock)
public bool DisableUserUiHide { get; set; }

// Disable hiding during cutscenes
public bool DisableCutsceneUiHide { get; set; }

// Disable hiding during GPose
public bool DisableGposeUiHide { get; set; }
Example:
// Keep overlay visible during cutscenes
this.PluginInterface.UiBuilder.DisableCutsceneUiHide = true;

UI State Properties

UiPrepared

Indicates whether the UI system is ready for use:
public bool UiPrepared { get; }

ShouldModifyUi

Indicates whether it’s safe to modify the game’s interface:
public bool ShouldModifyUi { get; }

CutsceneActive

Check if a cutscene is currently playing:
public bool CutsceneActive { get; }

FrameCount

Get the number of frames drawn since plugin creation:
public ulong FrameCount { get; }

Cursor Control

Override the game’s cursor with ImGui’s cursor:
// Enable ImGui cursor override
this.PluginInterface.UiBuilder.OverrideGameCursor = true;
Only set OverrideGameCursor to true when your plugin actively needs cursor control. Remember to set it back to false when done.

Accessibility Features

Reduced Motion

Check if users have enabled reduced motion:
if (this.PluginInterface.UiBuilder.ShouldUseReducedMotion)
{
    // Use minimal or no animations
}
else
{
    // Use full animations
}

Plugin UI Sound Effects

Check if sound effects are enabled for plugin windows:
if (this.PluginInterface.UiBuilder.PluginUISoundEffectsEnabled)
{
    // Sound effects will play when windows open/close
}

Waiting for UI

If you need to perform operations that require the UI to be ready, use WaitForUi:
await this.PluginInterface.UiBuilder.WaitForUi();
// UI is now ready
Or run a function when UI is prepared:
var result = await this.PluginInterface.UiBuilder.RunWhenUiPrepared(() =>
{
    // This runs when UI is ready
    return someValue;
}, runInFrameworkThread: true);

Device and Window Handles

Access Direct3D and window handles for advanced scenarios:
// Get Direct3D device handle
nint deviceHandle = this.PluginInterface.UiBuilder.DeviceHandle;

// Get main window handle
nint windowHandle = this.PluginInterface.UiBuilder.WindowHandlePtr;
These handles should only be used by advanced plugins that need direct access to rendering resources. Improper use can cause crashes.

ResizeBuffers Event

Handle DirectX buffer resize events:
this.PluginInterface.UiBuilder.ResizeBuffers += () =>
{
    // Clean up and recreate DirectX resources
};

Style and Font Change Events

React to changes in Dalamud’s default styling:
this.PluginInterface.UiBuilder.DefaultStyleChanged += () =>
{
    // Reload style-dependent resources
};

this.PluginInterface.UiBuilder.DefaultFontChanged += () =>
{
    // Reload font-dependent resources  
};

this.PluginInterface.UiBuilder.DefaultGlobalScaleChanged += () =>
{
    // Adjust UI for new scale
};

ULD Files

Load game UI asset files (ULD format):
var uld = this.PluginInterface.UiBuilder.LoadUld("ui/uld/LookingForGroup.uld");

Best Practices

1
Subscribe to Events in Constructor
2
Subscribe to Draw and other events during plugin initialization.
3
Always Unsubscribe
4
Unsubscribe from all events in your Dispose method to prevent memory leaks.
5
Check State Properties
6
Use UiPrepared and ShouldModifyUi before performing UI operations that depend on game state.
7
Respect User Preferences
8
Honor the ShouldUseReducedMotion and automatic hiding settings.
9
Handle Exceptions
10
Wrap your Draw code in try-catch blocks to prevent crashes from breaking the entire UI.

Complete Example

public class ExamplePlugin : IDalamudPlugin
{
    private DalamudPluginInterface PluginInterface { get; init; }
    private bool isVisible = true;
    private bool configVisible = false;
    
    public ExamplePlugin(DalamudPluginInterface pluginInterface)
    {
        this.PluginInterface = pluginInterface;
        
        // Subscribe to events
        pluginInterface.UiBuilder.Draw += DrawUI;
        pluginInterface.UiBuilder.OpenConfigUi += ToggleConfig;
        pluginInterface.UiBuilder.ShowUi += () => this.isVisible = true;
        pluginInterface.UiBuilder.HideUi += () => this.isVisible = false;
        
        // Configure UI behavior
        pluginInterface.UiBuilder.DisableCutsceneUiHide = false;
    }
    
    private void DrawUI()
    {
        if (!this.isVisible) return;
        
        ImGui.Begin("Example Plugin");
        ImGui.Text($"Frame: {this.PluginInterface.UiBuilder.FrameCount}");
        
        if (ImGui.Button("Open Config"))
        {
            this.configVisible = true;
        }
        ImGui.End();
        
        if (this.configVisible)
        {
            DrawConfigWindow();
        }
    }
    
    private void DrawConfigWindow()
    {
        ImGui.Begin("Configuration", ref this.configVisible);
        ImGui.Text("Plugin settings go here");
        ImGui.End();
    }
    
    private void ToggleConfig()
    {
        this.configVisible = !this.configVisible;
    }
    
    public void Dispose()
    {
        this.PluginInterface.UiBuilder.Draw -= DrawUI;
        this.PluginInterface.UiBuilder.OpenConfigUi -= ToggleConfig;
    }
}

See Also

  • Drawing Windows - Using the WindowSystem for managed window rendering
  • ImGui Basics - Introduction to ImGui controls and layout
  • Fonts - Working with custom fonts
  • Textures - Loading and displaying images

Build docs developers (and LLMs) love