# How to Customize Sniffnet's Appearance with Custom Themes: A Complete Guide

> Customize Sniffnet's appearance with custom themes. Learn how to create a TOML file with hex colors and load it via settings or use the style path for automatic theme application.

- Repository: [Giuliano Bellini/sniffnet](https://github.com/GyulyVGC/sniffnet)
- Tags: how-to-guide
- Published: 2026-04-28

---

**Create a TOML file containing six hexadecimal color values and load it through the Appearance settings page, or set the `style_path` field in your configuration file to apply a custom theme automatically.**

Sniffnet's interface is controlled by a flexible style system centered on the `StyleType` enum, which maps predefined palettes or user-defined TOML configurations to the application's visual elements. Whether you want to match your system theme or create a unique look for network monitoring, you can customize Sniffnet's appearance without modifying source code. This guide walks you through the architecture, file formats, and implementation details found in the `GyulyVGC/sniffnet` repository.

## How Sniffnet's Theme System Works

### The StyleType Enum and Palette Architecture

The theme engine revolves around the `StyleType` enum defined in [`src/gui/styles/types/style_type.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/style_type.rs), which includes variants for built-in themes like `A11yDark` and `DraculaLight`, plus a `Custom(CustomPalette)` variant for user-defined schemes. Each theme maps to a `Palette` struct containing six core color fields that drive the entire UI appearance according to the implementation in [`src/gui/styles/types/palette.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/palette.rs). The system separates declaration from rendering: color definitions live in TOML files, while runtime representation uses the `CustomPalette` wrapper found in [`src/gui/styles/types/custom_palette.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/custom_palette.rs).

When loaded, the palette automatically generates a `PaletteExtension` through `Palette::generate_palette_extension`, which computes derived UI parameters including button colors, night-mode detection, and alpha transparency values. This architecture ensures that custom themes automatically adapt UI components without requiring manual adjustments to every widget style.

## Creating Your Custom Theme File

### Required TOML Structure

Custom themes require a TOML file with exactly six hexadecimal color values. The `Palette::from_file` function in [`src/gui/styles/types/palette.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/palette.rs) validates these entries at load time, accepting both `#RRGGBB` and `#RRGGBBAA` formats.

Create a file (e.g., [`my_theme.toml`](https://github.com/GyulyVGC/sniffnet/blob/main/my_theme.toml)) with these required keys:

- `primary`: Background and main UI elements
- `secondary`: Incoming connections and headers
- `outgoing`: Outgoing connections visualization
- `starred`: Favorite items and star indicators
- `text_headers`: Header and footer text colors
- `text_body`: Body text and button labels

### Example Custom Theme

Reference the built-in themes in `resources/themes/` (such as [`catppuccin.toml`](https://github.com/GyulyVGC/sniffnet/blob/main/catppuccin.toml)) for complete implementations. A minimal custom theme looks like this:

```toml
primary       = "#1e1e2e"
secondary     = "#f5e0dc"
outgoing      = "#f5c2e7"
starred       = "#f9e2af"
text_headers  = "#cba6f7"
text_body     = "#d9e0ee"

```

Save this file anywhere on your filesystem; Sniffnet reads the absolute path stored in the configuration to locate your theme.

## Loading and Applying Custom Themes

### Via the Appearance Settings Page

The settings interface in [`src/gui/pages/settings_style_page.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/pages/settings_style_page.rs) provides a "Custom style" button that triggers a file dialog. When selected, the path generates a `Message::LoadStyle(path)` event that updates `Settings.style_path` and wraps the loaded palette in `StyleType::Custom`.

The UI previews your theme immediately using:

```rust
let custom_palette = Palette::from_file(custom_path);
if let Some(palette) = custom_palette {
    // Preview the freshly-loaded file
    palette
}

```

The `is_custom_toml_style_set` flag tracks whether a custom theme is active, allowing the application to display the current palette or the preview based on selection state.

### Via Configuration File

For automatic loading at startup, edit `~/.config/sniffnet/settings.toml` and set the absolute path:

```toml
style_path = "/absolute/path/to/my_theme.toml"

```

During initialization in [`src/gui/sniffer.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/sniffer.rs), the application executes:

```rust
self.conf.settings.style_path.clone_from(&path);
self.conf.settings.style = StyleType::Custom(CustomPalette::from_palette(palette));

```

This applies your custom theme before the main window renders, eliminating the need to use the GUI file picker on every launch.

## Validating and Debugging Theme Changes

After loading, verify the active palette at runtime by checking the `StyleType` variant:

```rust
if let StyleType::Custom(custom) = sniffer.conf.settings.style {
    println!("Custom palette loaded: {:?}", custom.palette);
}

```

The `PaletteExtension` computed by `CustomPalette::from_palette` automatically adjusts button colors and night-mode flags based on your primary color brightness. If colors fail to load, check that all six keys are present in your TOML file and that hex values are properly formatted, as `Palette::from_file` returns `None` for invalid inputs.

## Summary

- **Sniffnet uses a `StyleType` enum** in [`src/gui/styles/types/style_type.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/style_type.rs) to manage both built-in and custom themes through the `Custom` variant.
- **Create TOML files** with six required color keys (`primary`, `secondary`, `outgoing`, `starred`, `text_headers`, `text_body`) and valid hex values.
- **Apply themes via GUI** using the Appearance settings page, or **set `style_path`** in `~/.config/sniffnet/settings.toml` for automatic startup loading.
- **Runtime validation** occurs through `Palette::from_file`, which returns `None` for malformed files and automatically generates derived UI parameters via `PaletteExtension`.

## Frequently Asked Questions

### What file format does Sniffnet use for custom themes?

Sniffnet uses TOML files with six specific color keys. According to the implementation in [`src/gui/styles/types/palette.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/palette.rs), the file must define `primary`, `secondary`, `outgoing`, `starred`, `text_headers`, and `text_body` using hexadecimal color values. The loader accepts standard `#RRGGBB` or `#RRGGBBAA` formats and validates each entry during the `Palette::from_file` call.

### Where does Sniffnet store the active custom theme path?

The active theme path persists in the `Settings` struct's `style_path` field, defined in [`src/gui/types/settings.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/types/settings.rs). When you select a custom theme through the GUI, the application updates this field and saves it to `~/.config/sniffnet/settings.toml`. The `Sniffer` implementation in [`src/gui/sniffer.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/sniffer.rs) reads this path at startup to initialize the custom palette before rendering the interface.

### Can I switch between built-in and custom themes without restarting Sniffnet?

Yes. The Appearance settings page in [`src/gui/pages/settings_style_page.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/pages/settings_style_page.rs) handles live theme switching. When you load a custom TOML file, the application immediately dispatches `Message::LoadStyle` to update the configuration and rebuilds the UI with the new palette. You can switch back to built-in variants like `A11yDark` or `DraculaLight` through the same interface without closing the application.

### How does Sniffnet validate my custom theme colors?

Validation occurs in `Palette::from_file` within [`src/gui/styles/types/palette.rs`](https://github.com/GyulyVGC/sniffnet/blob/main/src/gui/styles/types/palette.rs). The function attempts to parse each TOML entry as a valid hex color and returns `None` if any key is missing or malformed. Once loaded, `CustomPalette::from_palette` generates a `PaletteExtension` that automatically calculates derived properties like button colors and night-mode detection, ensuring your theme remains functional even if you only specify the six base colors.