# How to Load and Use Multiple Fonts with ImFontAtlas in Dear ImGui

> Quickly load and use multiple fonts in Dear ImGui by adding fonts to ImFontAtlas with AddFontFromFileTTF and managing them with PushFont and PopFont for dynamic control.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-15

---

**To load and use multiple fonts with ImFontAtlas, add each font to `io.Fonts` before the first frame using `AddFontFromFileTTF()`, store the returned `ImFont*` pointers, and switch between them at runtime with `ImGui::PushFont()` and `ImGui::PopFont()`.**

Dear ImGui manages all fonts through a single **ImFontAtlas** object accessed via `ImGui::GetIO().Fonts`. According to the [ocornut/imgui](https://github.com/ocornut/imgui) source code, the atlas builds a unified texture containing every glyph from every font you add, allowing you to load and use multiple fonts with ImFontAtlas efficiently in a single draw call.

## Understanding the ImFontAtlas Architecture

The `ImFontAtlas` class, defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 761-777), acts as a container and rasterizer for all your fonts. When you call `AddFontFromFileTTF()` or similar methods, the atlas populates an internal texture atlas that the renderer uploads to the GPU. This design means you can load dozens of fonts and variants without changing your rendering pipeline.

In [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) (lines 45-53), the default context initialization ensures `io.Fonts` is never null, automatically calling `AddFontDefault()` if you haven't added any custom fonts before the first frame.

## Loading Multiple Fonts Before the First Frame

You must create all fonts after `ImGui::CreateContext()` but before the first call to `ImGui::NewFrame()`. This timing ensures the atlas builds correctly and your renderer uploads the texture once.

### Basic Font Loading with AddFontFromFileTTF

The primary method for loading TTF files is `ImFontAtlas::AddFontFromFileTTF()`, implemented in [`imgui_draw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_draw.cpp) (lines 3239-3245). Each call returns an `ImFont*` pointer that you should store if you intend to switch to that font later.

```cpp
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();

// Load different fonts with specific sizes
ImFont* font_mono = io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 16.0f);
ImFont* font_large = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 24.0f);

```

### Loading the Default Font

If you need a guaranteed fallback, call `AddFontDefault()` first. This embedded font loads instantly and serves as a backup when file-based fonts fail to load.

```cpp
ImFont* font_default = io.Fonts->AddFontDefault();  // Proggy Clean, 13px

```

## Configuring Fonts with ImFontConfig

The `ImFontConfig` struct gives you fine-grained control over rasterization, merging, and glyph selection. Pass a pointer to this struct as the third parameter to `AddFontFromFileTTF()`.

### Merging Icon Fonts into the Main Font

To render icons alongside text without `PushFont` calls, use `MergeMode`. Set `ImFontConfig::MergeMode = true` on secondary fonts to combine their glyphs into the previously added font's texture space.

```cpp
ImFont* main_font = io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f);

ImFontConfig icons_cfg;
icons_cfg.MergeMode = true;                    // Merge into previous font
icons_cfg.GlyphMinAdvanceX = 13.0f;            // Align icons width

static const ImWchar icon_ranges[] = { 0xF000, 0xF3FF, 0 };
ImFont* font_icon = io.Fonts->AddFontFromFileTTF(
    "fonts/fontawesome-webfont.ttf", 13.0f, &icons_cfg, icon_ranges);

```

Now `main_font` contains both text and icon glyphs, letting you write:

```cpp
ImGui::Text("Camera %s", ICON_FA_CAMERA);  // No font switching needed

```

### Setting Custom Glyph Ranges

For Chinese, Japanese, or Korean text, specify Unicode ranges to avoid loading the entire font:

```cpp
static const ImWchar ranges[] = { 0x0020, 0x00FF, 0x3000, 0x30FF, 0 };
ImFontConfig cfg;
ImFont* font_jp = io.Fonts->AddFontFromFileTTF("fonts/NotoSansJP.ttf", 18.0f, &cfg, ranges);

```

## Building the Font Atlas

ImGui automatically builds the atlas on the first call to `NewFrame()` if any fonts were added or configurations changed. However, you can force immediate building with `Build()`:

```cpp
io.Fonts->Build();  // Optional: forces rasterization before first frame

```

If you add fonts after the first frame (hot-reloading), you must call `Build()` and refresh your renderer's device objects. Most backends provide `ImGui_ImplXXX_CreateDeviceObjects()` for this purpose.

## Switching Between Fonts at Runtime

To render text in a specific font, use the stack-based `PushFont`/`PopFont` API.

### The PushFont/PopFont Pattern

Surround your UI code with these calls to temporarily change the font:

```cpp
ImGui::PushFont(font_mono);
ImGui::Text("Code sample: int x = 42;");
ImGui::PopFont();  // Restore previous font

```

You can nest these calls safely. The example in [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp) (lines 3768-3792) demonstrates loading several fonts and switching between them for headers and body text:

```cpp
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontDefault();
ImFont* large = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 24.0f);
ImFont* small = io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 12.0f);

// Usage
ImGui::PushFont(large);
ImGui::Text("Large heading");
ImGui::PopFont();

ImGui::PushFont(small);
ImGui::Text("Small footnote");
ImGui::PopFont();

```

### Using the Default Font

If you never call `PushFont`, ImGui uses the first font added (the default). If you only loaded `AddFontDefault()`, that becomes your primary font.

## Hot-Reloading Fonts After Initialization

To update fonts at runtime (e.g., changing sizes based on DPI):

1. Clear existing fonts: `io.Fonts->Clear()`
2. Re-add your fonts with new configurations
3. Call `io.Fonts->Build()`
4. Refresh GPU textures via your backend's recreation function

```cpp
// Clear and reload
io.Fonts->Clear();
ImFont* new_font = io.Fonts->AddFontFromFileTTF("fonts/Arial.ttf", new_size);
io.Fonts->Build();

// Backend-specific texture refresh
ImGui_ImplOpenGL3_CreateDeviceObjects();

```

## Summary

- **Load early**: Add fonts after `CreateContext()` but before the first `NewFrame()` to avoid rebuilding.
- **Store pointers**: Keep the `ImFont*` returned by `AddFontFromFileTTF()` for later use with `PushFont`.
- **Merge icons**: Use `ImFontConfig::MergeMode = true` to combine icon fonts with text fonts, eliminating the need for `PushFont` swaps.
- **Switch at runtime**: Use `PushFont(font)` and `PopFont()` to change fonts for specific widgets.
- **Rebuild when changing**: Call `io.Fonts->Build()` and refresh backend device objects if you modify fonts after the first frame.

## Frequently Asked Questions

### Can I load fonts after the first frame has already rendered?

Yes, but you must manually trigger a rebuild. Call `io.Fonts->Clear()`, re-add your fonts, then `io.Fonts->Build()`. Finally, call your renderer backend's device object creation function (such as `ImGui_ImplOpenGL3_CreateDeviceObjects()`) to upload the new texture atlas to the GPU.

### How do I use an icon font like FontAwesome with a regular text font?

Add the text font first, then configure an `ImFontConfig` with `MergeMode = true` and pass the specific icon Unicode ranges to `AddFontFromFileTTF()`. This merges the icon glyphs into the same font atlas slot, allowing you to render text and icons together without `PushFont` calls.

### What happens if I don't call PushFont before drawing text?

If you never push a custom font, Dear ImGui uses the **default font**—the first one added to the atlas, or the built-in Proggy Clean font if you called `AddFontDefault()`. The default font is automatically selected when no other font is on the stack.

### Why are my custom fonts not appearing or showing as blank boxes?

This usually happens when the font file path is incorrect or the atlas failed to build. Verify the file exists at the specified path relative to your working directory. Also ensure you are loading fonts before the first `NewFrame()` call, or if loading later, that you called `Build()` and refreshed your renderer's textures. Blank boxes typically indicate missing glyphs in the atlas.