Install themes

Install GTK, icon, shell, and cursor themes on Fedora through DNF packages or manual extraction, then apply them via GNOME Tweaks or the KDE System Settings.

The scenario

You just upgraded to Fedora 41 and the default Adwaita theme feels too bright for your late-night coding sessions. You found a dark GTK theme on a GitHub repository, downloaded the archive, extracted it, and restarted GNOME. Nothing changed. The window borders stayed light. The menus stayed light. You check Tweaks, and the theme name is not in the dropdown. You are not alone. Theme installation on Linux looks simple until you hit the filesystem layout, the Flatpak sandbox, or the GNOME Shell extension requirement. This guide walks through the exact paths, the correct commands, and the hidden dependencies that keep custom themes from loading.

What is actually happening

Fedora does not use a single monolithic theme engine. The desktop environment splits visual styling into separate layers. GTK applications read CSS and JSON metadata from specific directories. GNOME Shell reads a separate shell theme directory. KDE Plasma uses a completely different configuration system based on Qt and Breeze. When you install a theme, you are not just dropping files into a folder. You are placing metadata files where the toolkit expects them, setting a registry key that tells the session to load that metadata, and sometimes installing a browser extension or a portal helper to bridge sandboxed applications.

The filesystem layout follows a strict priority order. User-local directories override system-wide directories. System-wide directories override package manager defaults. If you place a theme in the wrong directory, the toolkit will ignore it entirely. If you place it in a directory that requires root permissions, you risk breaking the package manager ability to manage your system. Understanding this hierarchy prevents permission errors and keeps your system upgrade path clean.

GTK3 and GTK4 parse theme files differently. GTK3 relies on gtk.css and gtk-dark.css inside the theme directory. GTK4 uses a compiled binary format called gtk4.css or falls back to the GTK3 CSS if the binary is missing. Libadwaita applications, which dominate modern Fedora, ignore traditional GTK themes entirely unless the theme explicitly ships a libadwaita/ subdirectory with matching CSS. This is why some themes look perfect in older applications but break in newer ones. The toolkit validates the directory structure before loading anything.

Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. The same rule applies to theme directories. /usr/share/themes belongs to dnf. ~/.local/share/themes belongs to you. Keep them separate.

The fix: installing and applying themes

Start with the package manager whenever possible. Fedora maintains a curated set of themes in the official repositories. These packages handle dependencies, metadata placement, and automatic updates. Run the search command to see what is available.

# List available theme packages without installing anything
dnf search theme | grep -i gtk
# Filter results to avoid pulling in unrelated desktop components

Pick a package that matches your toolkit. Install it with the standard transaction command. The package manager places files in /usr/share/themes and /usr/share/icons, which are read-only for normal users but fully managed by dnf.

# Install a GTK theme and its matching icon set
sudo dnf install -y numix-gtk-theme numix-icon-theme
# The package manager handles directory creation and metadata validation

Manual installation requires placing files in the correct user directory. Modern GNOME expects themes in ~/.local/share/themes rather than the legacy ~/.themes path. The legacy path still works on older releases, but the new path aligns with the XDG Base Directory Specification. Create the directory structure first.

# Create the modern user theme directory if it does not exist
mkdir -p ~/.local/share/themes ~/.local/share/icons
# The -p flag prevents errors if the parent directories already exist

Extract the archive directly into that directory. The extraction must preserve the top-level folder name. If the archive contains a flat list of files instead of a parent directory, the theme will fail to load.

# Extract the theme archive into the user directory
tar -xzf MyTheme.tar.gz -C ~/.local/share/themes/
# The -C flag changes to the target directory before extracting files

Apply the theme through the command line to avoid GUI lag or caching issues. gsettings writes directly to the dconf database and triggers a session update.

# Tell GTK to use the new theme for application windows
gsettings set org.gnome.desktop.interface gtk-theme 'MyTheme'
# Tell GTK to use the matching icon set
gsettings set org.gnome.desktop.interface icon-theme 'MyIcons'
# Tell GTK to use the custom cursor pack
gsettings set org.gnome.desktop.interface cursor-theme 'MyCursor'

GNOME Shell requires an extra step. The shell does not load user themes by default for security and stability reasons. You must install the User Themes extension. The extension acts as a bridge that tells the shell to read the theme directory instead of using the built-in Adwaita shell theme.

# Install the extension package from the official repository
sudo dnf install -y gnome-shell-extension-user-theme
# The package places the JS extension in /usr/share/gnome-shell/extensions/

Enable the extension through the Extensions application or via gnome-extensions enable. Once enabled, the shell theme dropdown appears in Tweaks. Select your shell theme and restart the shell session. Press Alt+F2, type r, and press Enter to reload the shell without logging out. On Wayland, the r shortcut does not work. You must log out and log back in to apply shell theme changes.

Verify it worked

Check the active theme configuration to confirm the registry updated correctly. The gsettings get command reads the current value from the dconf database.

# Verify the active GTK theme name
gsettings get org.gnome.desktop.interface gtk-theme
# Verify the active icon theme name
gsettings get org.gnome.desktop.interface icon-theme

Open a GTK application like Files or Text Editor. The window decorations, menus, and buttons should reflect the new theme. Open the GNOME Shell overview by pressing the Super key. The top bar, dock, and calendar popover should match the shell theme. If the shell theme did not change, the User Themes extension is either disabled or the shell theme directory structure is incorrect.

Run journalctl -xe to read the actual error before guessing. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu gnome-shell muscle-memory style. Look for Gtk-WARNING or Failed to load theme messages. They tell you exactly which file the toolkit tried to read and why it failed.

Common pitfalls and error patterns

Flatpak applications run in a sandbox that isolates them from the host filesystem. By default, Flatpaks cannot read ~/.local/share/themes or /usr/share/themes. They will continue using the bundled Adwaita theme even after you change the host settings. The xdg-desktop-portal-gtk package bridges this gap by forwarding theme preferences to sandboxed applications. Install it if your Flatpaks ignore your custom theme.

# Install the portal helper that forwards theme settings to Flatpaks
sudo dnf install -y xdg-desktop-portal-gtk
# The portal runs as a background service and translates host preferences

Some themes ship with broken metadata files. The index.theme file inside an icon pack must declare the correct directory structure. If the file points to a missing scalable or 256x256 directory, GNOME will fall back to the default icons. Check the journal for toolkit warnings when an application launches.

# Search the journal for GTK theme loading errors
journalctl -xeu gnome-shell | grep -i "theme\|icon\|gtk"
# Filter output to isolate toolkit warnings and missing file paths

Editing files in /usr/share/themes directly breaks package management. The dnf command will overwrite your changes during the next system update. Always use user-local directories or create a drop-in configuration in /etc/xdg/ if you are managing a fleet of machines. Trust the package manager for system-wide changes. Use user directories for personal customization.

SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. If you copied a theme into a directory with the wrong context, the toolkit will silently refuse to read it. Run restorecon -Rv ~/.local/share/themes/ to fix context mismatches. The command resets security labels to the expected defaults without deleting your files.

KDE Plasma handles themes differently. The desktop environment reads configuration from ~/.config/plasma-org.kde.plasma.desktop-appletsrc and applies changes through the System Settings GUI. You can install community themes via dnf, but the package manager only places the files. You still need to open System Settings, navigate to Appearance, and select the theme manually. KDE does not use gsettings. It uses kwriteconfig5 or kwriteconfig6 under the hood.

# Install a GTK theme that KDE can use for GTK applications
sudo dnf install -y breeze-gtk
# KDE uses this package to theme GTK apps running inside Plasma

When to use which method

Use dnf install when you want automatic updates, dependency resolution, and system-wide availability. Use manual extraction to ~/.local/share/themes when you are testing an unreleased theme or a personal fork. Use gsettings when you need to script theme switching or apply changes across multiple machines. Use the User Themes extension when you want to change the GNOME Shell top bar and dock appearance. Use xdg-desktop-portal-gtk when your Flatpak applications refuse to adopt the host theme. Stay on the default Adwaita theme if you prioritize battery life and want zero configuration drift.

Reboot before you debug. Half the time the symptom is gone.

Where to go next