thisfrontenddev/agent-skills · Archived

rofi-rasi-theming

Use when creating, editing, or debugging rofi themes (.rasi files), designing rofi launcher UIs, or when the user asks to customize rofi appearance — covers the full RASI styling system including widget tree, box model, properties, gradients, media queries, layout tricks, and hard limitations

First seen Mar 6, 2026

Installation

$ npx skills add thisfrontenddev/agent-skills --skill rofi-rasi-theming

Summary

Use when creating, editing, or debugging rofi themes (.rasi files), designing rofi launcher UIs, or when the user asks to customize rofi appearance — covers the full RASI styling system including widget tree, box model, properties, gradients, media queries, layout tricks, and hard limitations

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

License MIT
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents cursor

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 17,361 B
  • docs SUMMARY.md 320 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Rofi RASI Theming

Overview

RASI (Rofi Advanced Style Information) is a CSS-inspired theming system for rofi 2.0+. It provides a fixed widget tree with box-model styling, global variables, calc(), @media queries, and linear gradients. Think CSS circa 2008 + custom properties + calc() applied to a box-packing layout engine. No animations, no transforms, no hover states.

When to Use

  • User wants to create or modify a .rasi theme
  • Porting a color scheme / design to rofi
  • Debugging layout or styling issues in rofi
  • Building creative layouts (grid launchers, decorated panels, Spotlight-style bars)

Widget Tree

Fixed hierarchy — you cannot invent widget types, but you CAN restructure with children: and inject custom widgets via naming prefixes.

window
+-- overlay
+-- mainbox                          [vertical box]
    +-- inputbar                     [horizontal box]
    |   +-- prompt                   [textbox]
    |   +-- textbox-prompt-colon     [textbox]
    |   +-- entry                    [textbox]
    |   +-- case-indicator           [textbox]
    |   +-- num-filtered-rows        [textbox]
    |   +-- textbox-num-sep          [textbox]
    |   +-- num-rows                 [textbox]
    |   +-- textbox-current-entry    [textbox]
    |   +-- icon-current-entry       [icon]
    +-- message                      [container]
    |   +-- textbox                  [textbox]
    +-- listview                     [list container]
    |   +-- scrollbar
    |   +-- element                  [box, repeated per row]
    |       +-- element-icon         [icon]
    |       +-- element-index        [textbox]
    |       +-- element-text         [textbox]
    +-- mode-switcher                [horizontal box]
        +-- button                   [textbox, per mode]

Error variant: window -> error-message [vbox] -> textbox

Custom Widget Prefixes

Create custom widgets by naming convention — rofi infers the type:

Prefix Type Key properties
textbox-* Read-only text content, markup
icon-* Icon display filename, size, tint
button-* Clickable text content, action
Any other Box container children, orientation, spacing
mainbox {
    children: [ textbox-header, inputbar, textbox-divider, listview ];
}
textbox-header {
    content: "  Applications";
    background-color: @accent;
    text-color: @bg;
    padding: 12px;
    font: "GeistMono Nerd Font Bold 14";
}
textbox-divider {
    content: "";
    background-color: @accent;
    padding: 2px; /* colored line separator */
}

Box Model

Identical to CSS. Per-side shorthand works for margin, padding, border, border-radius:

padding: 10px;                   /* all sides */
padding: 10px 20px;             /* vertical horizontal */
padding: 10px 20px 30px;        /* top horizontal bottom */
padding: 10px 20px 30px 40px;   /* top right bottom left */
border: 2px solid;              /* width + style (solid|dash) */

Properties Quick Reference

Window

Property Type Example
font Pango string "GeistMono Nerd Font 12"
transparency String "real", "background", "screenshot", "path.png"
location Position center, north, south east, etc.
anchor Position Anchor point on the window
fullscreen Boolean
width Distance 800px, 50%, calc(50% min 800px)
x-offset, y-offset Distance

Universal (all widgets)

Property Type Notes
enabled Boolean Show/hide
background-color Color RGBA, hex, named
background-image Image linear-gradient(), url()
text-color Color
font Pango string Per-widget override
border Border 2px solid, per-side shorthand
border-color Color
border-radius Distance Per-corner shorthand, 999px for pill
margin Distance Per-side shorthand
padding Distance Per-side shorthand
cursor Keyword default, pointer, text

Box / Container

Property Type Notes
orientation Keyword horizontal, vertical
spacing Distance Gap between children
children List Widget names to pack

Textbox / Entry / Prompt

Property Type Notes
content / str String Display text (textbox-* only)
markup Boolean Enable Pango markup
highlight Style + Color Matched-text styling
vertical-align Real 0.0-1.0
horizontal-align Real 0.0-1.0
text-transform Keyword uppercase, lowercase, none
expand Boolean Consume remaining space
placeholder String Empty-state text
placeholder-color Color
blink Boolean Cursor blink
cursor-width Distance
cursor-color Color
text-outline Boolean
text-outline-width Double
text-outline-color Color
tab-stops Distance[] Tab stop positions

Listview

Property Type Notes
columns Integer Number of columns (grid)
lines Integer Visible rows
fixed-height Boolean Don't shrink
fixed-columns Boolean
dynamic Boolean Resize on filter
scrollbar Boolean
cycle Boolean Wrap navigation
layout Keyword horizontal, vertical
flow Keyword Packing direction
reverse Boolean
require-input Boolean Hide until typing

Icon / element-icon

Property Type Notes
filename String Path or theme icon name
size Distance e.g. 32px
squared Boolean Force square
tint Color Color overlay

Scrollbar

Property Type
handle-width Distance
handle-color Color
handle-rounded-corners Boolean

States and Selectors

No CSS selectors. Target widgets by name, append state modifiers. Two axes multiply:

| | .normal | .urgent | .active | |--|-----------|-----------|-----------| | normal | element normal.normal | element normal.urgent | element normal.active | | selected | element selected.normal | element selected.urgent | element selected.active | | alternate | element alternate.normal | element alternate.urgent | element alternate.active |

alternate = hardcoded odd/even row striping. This is the only :nth-child equivalent.

Multiple selectors: entry, element-text { } (comma-separated).

Variables and Inheritance

/* Global scope only — defined in * {} */
* {
    bg: #1e1e2eff;
    fg: #cdd6f4ff;
    accent: #89b4faff;
    gap: 8px;
    radius: 8px;
}

window {
    background-color: @bg;
}

/* var() with fallback */
width: var(my-width, 50%);

/* env() for environment variables */
width: env(ROFI_WIDTH, 50%);

/* inherit from parent */
inputbar {
    background-color: inherit;
}

No scoped variables. Global * {} only. inherit pulls from parent widget.

calc()

Supported operators: +, -, *, /, modulo, min, max, floor, ceil, round.

window { width: calc(50% min 800px); }
listview { spacing: calc(1em / 2); }

@media Queries

Monitor-resolution-based (not window-based):

@media ( min-width: 2560 ) {
    listview { columns: 3; }
}
@media ( monitor-id: 0 ) {
    window { width: 30%; }
}
@media ( max-height: 768 ) {
    listview { lines: 5; }
}

Constraints: min-width, max-width, min-height, max-height, min-aspect-ratio, max-aspect-ratio, monitor-id, enabled.

Gradients and Images

/* Linear gradient — the only gradient type */
background-image: linear-gradient(to right, #ff000080, #0000ff80);
background-image: linear-gradient(45deg, #ff0000, #00ff00, #0000ff);

/* Image file — PNG primarily, SVG if compiled with librsvg */
background-image: url("/path/to/image.png", both);
/* Scale modes: none, both, width, height */

No radial-gradient, conic-gradient, repeating-linear-gradient. No background-size, background-position, background-repeat.

Imports and Composition

@import "filename"      /* Merge into current theme */
@theme "filename"       /* Wipe slate, load fresh */
?import "filename"      /* Optional — no error if missing */

Convention: .rasinc extension for partials. Typical modular pattern:

@theme "base-layout"
@import "~/.config/rofi/colors/palette.rasi"
/* then override specific properties */

Layout Patterns

Centering with expand (flexbox hack)

inputbar {
    children: [ dummy-left, entry, dummy-right ];
}
dummy-left { expand: true; }
dummy-right { expand: true; }

Horizontal launcher (Spotlight-style)

listview { layout: horizontal; lines: 1; columns: 8; }
element { orientation: vertical; }
element-icon { horizontal-align: 0.5; }
element-text { horizontal-align: 0.5; }

Grid launcher (3x3)

listview { columns: 3; lines: 3; fixed-columns: true; }
element { orientation: vertical; spacing: 16px; }
element-icon { horizontal-align: 0.5; vertical-align: 0.5; }
element-text { horizontal-align: 0.5; }

Pill-shaped input

entry {
    border-radius: 999px;
    padding: 8px 16px;
    border: 1px solid;
}

Transparency with depth

window {
    transparency: "real";
    background-color: transparent;
}
mainbox {
    background-image: linear-gradient(to bottom, #1e1e2ef2, #1e1e2ecc);
}

Decorative header + divider

mainbox {
    children: [ textbox-header, inputbar, textbox-sep, listview ];
}
textbox-header {
    content: "  Launch";
    background-color: @accent;
    text-color: @bg;
    padding: 12px;
}
textbox-sep {
    content: "";
    background-color: @accent;
    padding: 1px;
}

Monitor-responsive columns

@media ( min-width: 2560 ) {
    listview { columns: 3; }
}
@media ( max-width: 1920 ) {
    listview { columns: 1; }
}

Hard Stops — What RASI Cannot Do

Feature Status Workaround
Animations / transitions None Static only
:hover, :focus None Only the 9-state system
::before, ::after None Use textbox-* widgets
Box-shadow None Nested borders / compositor shadow
Text-shadow None text-outline is partial substitute
Transform (rotate/scale) None
Z-index / stacking None Widget order = paint order
Overflow control None Only listview scrolls
Position absolute/relative None Flow-based box packing only
Flexbox / CSS Grid None orientation + expand + spacing only
Radial/conic gradient None linear-gradient only
Scoped variables None Global * {} only
Selector specificity None Last-definition-wins
min-width/max-width on widgets None @media on monitor only
Per-character font fallback None Pango handles fallback
background-size/position/repeat None Only scale mode in url()

Swappable Theme Architecture

Separation of Concerns

Split rofi config into three layers:

~/.config/rofi/
  config.rasi              # Behavior only (modi, keybindings, matching, terminal)
  themes/
    cybrland.rasi          # Complete theme: layout + colors
    catppuccin-mocha.rasi  # Another complete theme
    minimal-dark.rasi      # Another
    shared/
      colors-catppuccin.rasinc   # Color-only partial (reusable)
      colors-cybrland.rasinc     # Color-only partial (reusable)
      layout-grid.rasinc         # Layout-only partial (reusable)
      layout-list.rasinc         # Layout-only partial (reusable)

config.rasi — Behavior Only

Keep config.rasi free of any visual styling. End it with a single @theme line:

configuration {
    modi: "drun,run,filebrowser";
    show-icons: true;
    font: "GeistMono Nerd Font 12";
    terminal: "ghostty";
    /* ... all behavior settings ... */
}
@theme "cybrland"

To swap themes, change only the @theme line. Everything else stays.

Theme File Resolution

When @theme "name" is used (no path, no extension), rofi searches:

  1. Relative to the file containing the @theme statement
  2. ~/.config/rofi/themes/
  3. ~/.config/rofi/
  4. ~/.local/share/rofi/themes/
  5. ${INSTALL_PREFIX}/share/rofi/themes/

It appends .rasi then .rasinc when resolving. So @theme "cybrland" finds ~/.config/rofi/themes/cybrland.rasi.

Full paths and ~/ expansion also work: @theme "~/dotfiles/rofi/mytheme.rasi".

Standalone Theme Structure

A complete swappable theme must be fully self-contained — it defines everything visual:

/* themes/catppuccin-mocha.rasi */

/* === Colors === */
* {
    bg:        #1e1e2ef2;
    surface:   #313244ff;
    fg:        #cdd6f4ff;
    accent:    #89b4faff;
    subtle:    #6c7086ff;
    urgent:    #f38ba8ff;
    gap:       8px;
    radius:    12px;
}

/* === Window === */
window {
    transparency:    "real";
    background-color: @bg;
    border:          2px solid;
    border-color:    @accent;
    border-radius:   @radius;
    width:           600px;
    location:        center;
}

/* === Layout === */
mainbox {
    background-color: transparent;
    padding:          @gap;
    children:         [ inputbar, listview ];
}

/* === Input === */
inputbar {
    /* ... */
}

/* === List === */
listview {
    /* ... */
}

/* === Elements + States === */
element normal.normal   { /* ... */ }
element selected.normal { /* ... */ }
element alternate.normal { /* ... */ }
/* ... all 9 states ... */

Composable Themes with Partials

For maximum reuse, split colors and layout into .rasinc partials and compose them:

/* themes/catppuccin-grid.rasi — composed theme */
@import "shared/colors-catppuccin.rasinc"
@import "shared/layout-grid.rasinc"

/* Theme-specific overrides */
window { width: 800px; }
/* themes/shared/colors-catppuccin.rasinc — color partial */
* {
    bg:      #1e1e2ef2;
    surface: #313244ff;
    fg:      #cdd6f4ff;
    accent:  #89b4faff;
    /* ... */
}
/* themes/shared/layout-grid.rasinc — layout partial */
window {
    transparency:    "real";
    background-color: @bg;
    border:          2px solid;
    border-color:    @accent;
    border-radius:   @radius;
    location:        center;
}
mainbox {
    children: [ inputbar, listview ];
    /* ... */
}
listview {
    columns: 3;
    lines: 3;
    /* ... */
}
/* ... full layout ... */

This lets you mix any color scheme with any layout: colors-catppuccin + layout-grid, colors-cybrland + layout-list, etc.

Key rule: Partials use .rasinc extension — this is the convention for files meant to be imported, not used standalone. Rofi resolves both .rasi and .rasinc but the naming signals intent.

CLI Override

Override the theme for a single invocation without touching config:

# Use a specific theme
rofi -show drun -theme catppuccin-mocha

# Use a full path
rofi -show drun -theme ~/.config/rofi/themes/minimal-dark.rasi

The -theme flag behaves like @theme — it wipes and replaces. Useful for testing new themes or binding different themes to different keybindings in sway:

# sway config — different launcher styles per keybind
bindsym $mod+space exec rofi -show drun -theme cybrland
bindsym $mod+r exec rofi -show run -theme minimal-dark

Theme Debugging

# Dump the fully resolved theme (all imports flattened)
rofi -dump-theme

# Dump with a specific theme applied
rofi -theme mytheme -dump-theme

# Preview without modifying config
rofi -show drun -theme mytheme

-dump-theme outputs the final computed RASI after all @theme/@import resolution — useful for debugging which values actually apply.

Common Mistakes

Forgetting inherit or transparent: Widgets default to a theme-default background. Set background-color: transparent; or inherit explicitly on containers you want see-through.

border-radius on children clipped by parent: If a child has rounded corners but the parent doesn't, the child's corners get hidden. Match or exceed parent radius.

expand: true fights: If multiple siblings expand, they split space equally. Use expand: false on fixed-size widgets and let only one expand.

@theme vs @import: @theme wipes everything first. If your overrides disappear, you probably used @theme when you meant @import.

Color format: Rofi accepts #RRGGBB, #RRGGBBAA, rgba(), argb:AARRGGBB. Be consistent — mixing formats causes confusion.

transparency: "real" requires compositor support: On Sway, ensure your compositor renders layer-shell surfaces with alpha. Without it, "real" transparency shows black instead of desktop.