Meet RustUI
Building user interfaces with the native Rust Oxide CUI can be a painful experience. Most developers spend hours battling float anchors, fixing broken layouts on odd screen resolutions, and digging through massive files where layout code and core plugin logic are completely mixed up. It gets messy quickly, which is why clean, modern interfaces are rarely seen on Rust servers.
Built as an extension on top of the native Oxide CUI foundation, it introduces a clean, declarative syntax that makes UI development straightforward and organized. It cuts out the mathematical guesswork so you can focus on building great features.
Key Features
-
Expressive Syntax:
RustUI injects the style engine directly into your component builder actions. This allows you to chain methods like
SetText()orSetWidth()instantly without messy, deeply nested code blocks. -
Contextual Payloads:
Every user interface can receive a contextual payload via its
Show()call. This lets you seamlessly pass game data, such as a clicked furnace or storage chest, directly into the UI window and completely eliminates the need for maintaining messy global dictionaries. -
Fluid Theming:
Crafting modern interfaces is incredibly simple. RustUI packs virtually every standard color right into its core. With fluent modifiers like
Darken(),Lighten(), and transparency controls, your components look elegant out of the box. -
Components:
Keep your codebase clean and modular by utilizing built-in components or composing your own custom, reusable interface components directly within your plugin.
-
Intuitive State Management:
Effortlessly change the state of your elements at runtime. With simple
Update()andRefresh()calls, or by binding powerful lambda actions directly to components, managing active user interaction becomes second nature. -
Inline Actions:
Eliminate the need for registering cluttered plugin commands. With inline actions, you can bind executable lambdas directly to buttons and text fields, allowing your interaction logic to run directly in your UI.
Installing RustUI
Getting started with RustUI is straightforward. Because RustUI is built as a native server extension rather than a standard Oxide plugin, it integrates directly into your server core to deliver maximum performance and fluid state management without runtime overhead.
Prerequisites
Before installing, ensure your Rust server meets the following criteria:
-
Rust Server Version
Protocol: 2632.287.1Build Date: 08/07/2026 11:36:35Unity Version: 6000.3.15x1-8Changeset: 160556Branch: release -
Oxide Version
Version: 2.0.7585Branch: master
You can use the version and oxide.version commands in your server console to verify if your Rust Server matches the prerequisites listed above.
Installation Steps
To install the framework, copy the Oxide.Ext.RustUI.dll extension file and place it directly into the RustDedicated_Data/Managed/ directory
Because RustUI loads as a native low-level assembly extension, a full server restart is required to mount the engine into the server memory. Once the server completes its boot cycle, RustUI is instantly active and ready to use.
Configuration
RustUI is completely ready out of the box, allowing you to dive straight into building a UI inside your Rust plugin.
Importing the Namespace
To begin utilizing RustUI within your Rust plugin, simply import the official framework namespace at the very top of your plugin file:
using Oxide.Ext.RustUI;
// your plugin class
That is all it takes to integrate the framework. With the namespace successfully imported and the extension running on your Rust Server, you have completely bypassed the limitations of the traditional interface engine. You are now fully equipped to move forward and start building your very first UI.
Architecture Concepts
To build beautiful and maintainable user interfaces, it is essential to understand how RustUI structures layout spaces under the hood. Traditional Rust Oxide UI development forces you to think in confusing, abstract float anchors and absolute screen coordinates. RustUI completely abandons this mathematical headaches by introducing a predictable, state-of-the-art rendering architecture inspired by the layout engines of modern web browsers.
Automatic Layout Computation
The core power of RustUI lies in its automated layout computation engine. In traditional CUI development, changing the size of a single element requires you to manually recalculate the positions of every surrounding component. RustUI handles this heavy lifting for you entirely out of the box.
The engine continuously monitors your component tree, automatically computing the exact structural dimensions and pixel values of every container in real time. Because the framework instantly understands the precise height and width of every element, you can build advanced, fluid layouts like dynamic scroll regions and complex grids without ever writing brittle mathematical formulas. If content changes, the layout automatically recalculates and shifts beautifully.
The Fluid Canvas & Inheritance
In RustUI, layout design follows a strict hierarchical inheritance pattern. By default, every child element you instantiate is automatically centered and stretches to inherit 100% of its parent container's width and height. This lets you nest components freely while maintaining relative structural control:
root.Panel((panel) =>
{
// Configure fixed boundaries for the parent container
panel.Style.SetWidth("600px")
.SetHeight("400px");
panel.Label((label) =>
{
// This label automatically inherits and fills 100% of the parent panel
// No anchors, no manual position guessing required
});
});
Whenever you need to deviate from this full-bleed default, you manipulate the element using expressive, native-feeling sizing parameters like SetWidth("100px") or intuitive percentages SetWidth("25%"). Furthermore, RustUI introduces native Flexbox capabilities into the Rust gaming context. You can align components horizontally or vertically, distribute space evenly, and let elements grow or shrink dynamically. The engine handles the responsive boundary shifts instantly behind the scenes, ensuring your interface renders flawlessly across all player monitor resolutions.
The RustUI Box Model
To guarantee that elements never overlap and visual borders align with absolute precision, RustUI implements a rigorous, automated 3-layer Box Model. Every standard visual component automatically encapsulates three distinct structural boundaries:
- The Outer Rect: The absolute boundary of the element, defining its total physical footprint inside the parent container.
- The Border Rect: An intelligent boundary layer nested inside the Outer Rect. If you define a custom border thickness, the engine automatically pushes this rect inward. This ensures your borders are rendered cleanly on the inside edges, preventing awkward visual spilling. Furthermore, each side can receive its own independent width configuration.
- The Padding Rect (Inner Rect): The final core layer nested safely inside the Border Rect. This canvas hosts the actual inner content, preserving an unbreachable protective margin around your elements.
Visually, the hierarchical computation flow of the box model engine coordinates your element spaces like this:
+---------------------------------------------------------+
| OUTER RECT (Total Physical Footprint) |
| +-----------------------------------------------------+ |
| | BORDER RECT (Custom Inside Edge Borders) | |
| | +-------------------------------------------------+ | |
| | | PADDING RECT (Inner Content Canvas) | | |
| | | | | |
| | | [ Your Label, Image or Widget Text Here ] | | |
| | | | | |
| | +-------------------------------------------------+ | |
| +-----------------------------------------------------+ |
+---------------------------------------------------------+
Non-Container Elements
While components like panels and buttons act as structural layout containers that can host child trees, certain elements serve purely as content terminals. In RustUI, image objects and text labels behave exactly like <img> tags in the modern web standard.
Because these elements are classified as non-containers, they cannot nest other child primitives. This architectural distinction guarantees maximum rendering performance on the server core, allowing the engine to compile and pass the final UI layout directly to the active player viewport with zero execution overhead.
Creating a UI
Every interface in RustUI starts with the RustUI.Create factory method. This method serves as the entry point for every UI you want to create.
RustUI ui = RustUI.Create(Ext.RustUI.Layer.Overlay, root =>
{
UIWindow window = root.Window;
});
Arg 1. Ext.RustUI.Layer
The first argument specifies the layer to bind your root element to. RustUI provides the following pre-defined layers matching the native Oxide layer stack:
Ext.RustUI.Layer.UnderExt.RustUI.Layer.UnderNonScaledExt.RustUI.Layer.MainExt.RustUI.Layer.HudExt.RustUI.Layer.HudMenuExt.RustUI.Layer.OverlayExt.RustUI.Layer.OverlayNonScaledExt.RustUI.Layer.OverallExt.RustUI.Layer.InventoryExt.RustUI.Layer.CraftingExt.RustUI.Layer.ContactsExt.RustUI.Layer.ClansExt.RustUI.Layer.TechTreeExt.RustUI.Layer.Map
To learn more about Layers, please consult the official Oxide CUI Layer Documentation.
Arg 2. Action
The final argument is an executable lambda that fires whenever the UI renders for a player. This closure provides three highly expressive parameters to construct your UI state:
root: The root container acting as the canvas for your UI. You will utilize this object to attach child elements like panels, labels, and buttons.root.Window: The Window Instance. This object contains the activeBasePlayer Playerviewing the UI, theUIPayload Payloadpassed to theShow()function, and the activeRustUI UIinstance itself.
A more complete example
Let's look at a complete example. Below, we define a new UI and implement a reactive button that dynamically updates a label's style at runtime:
RustUI ui = RustUI.Create(Ext.RustUI.Layer.Overlay, root =>
{
UIWindow window = root.Window;
// style our root element
root.Style.SetBlurBackground()
.SetKeyboardEnabled(true)
.SetCursorEnabled(true);
// create a flex column
root.FlexColumn((flexPanel) =>
{
// this styles the flex column with some basic styling
flexPanel.Style.SetBackgroundColor(Theme.Primary.Darken(60f, 0.98f))
.SetBorder("2px")
.SetBorderColor(Theme.Primary.Darken(80))
.SetOffset("50px", "50px", "50px", "50px");
// create a text label and give it an ID
flexPanel.Label("my_label", (label) =>
{
label.Style.SetText("Click on the button!")
.SetFontColor(Theme.Danger);
});
// create our button
flexPanel.Button((button) =>
{
button.Style.SetText("Click Me")
.SetBackgroundColor(Theme.Primary.Darken(10f))
.SetHoverColor(Theme.Primary.Lighten(10f));
// bind the inline click event
button.OnClick((Event) =>
{
// Reactively update the target element's style at runtime
window.Update("my_label", (style) =>
{
style.SetText($"{Event.Player.displayName} clicked the button")
.SetFontColor(Theme.Success);
});
});
});
});
});
// show the UI to a specific player
ui.Show(player);
Showing the UI
RustUI offers you various ways to show a UI
-
Show the UI for one specific player
If you want to show the UI just to one specific player then you can pass the BasePlayer object to the
Show()methodui.Show(player) -
Show the UI for all players
By omitting the player object allows you to broadcast the UI to all connected players simultaneously.
ui.Show() -
Show the UI for a defined set of players
You may also want to show the UI to a specific set of players, you can achieve this by passing a
ListHashSet<BasePlayer>to theShow()method.ui.Show({ player1, player2 })
Passing a payload to the UI
You may want to pass data to the UI so it know in what context it should build the UI, for example, you want to show a player profile, in this case you need to tell the UI for which player it should create the profile layout. You can achieve this by passing a UIPayload object using tuples
ui.Show(player, new UIPayload(
("profilePlayer", otherPlayer)
))
Retrieving payload data
After passing a payload to the UI you can retrieve the data like so
ui = RustUI.Create(Ext.RustUI.Layer.Overlay, root =>
{
UIWindow window = root.Window;
UIPayload payload = window.Payload;
// retrieve the profile player from the passed payload
BasePlayer profilePlayer = payload.Get<BasePlayer>("profilePlayer");
root.Label((label) =>
{
label.Style.SetText($"Profile for {profilePlayer.displayName}");
});
});
Hiding the UI
Just like showing the UI, RustUI offers also various ways to hide the UI
-
Hide the UI for one specific player
If you want to hide the UI just to one specific player then you can pass the BasePlayer object to the
Hide()methodui.Hide(player) -
Hide the UI for all players
By omitting the player object allows you to hide the UI to all connected players simultaneously.
ui.Hide() -
Hide the UI for a defined set of players
You may also want to hide the UI for a specific set of players, you can achieve this by passing a
ListHashSet<BasePlayer>to theHide()method.ui.Hide({ player1, player2 })
Updating Elements
After the UI is shown to the player you are able to Update elements. Updating an element only renders that particular element without sending a fully re-rendered UI to the player. In order to update elements you are required to give the element an id
root.Panel("my_panel_id", panel =>
{
});
Now that RustUI is able to identify the panel, you are ready to manipulate the panel and stream te updated panel back to the player that is viewing the UI. Lets create a simpel button and change the background color of the panel to green when the player clicks the button
root.Panel("my_panel_id", panel =>
{
panel.Style.BackgroundColor("red");
});
root.Button(button =>
{
button.OnClick(Event =>
{
Event.Window.Update("my_panel_id", (style) =>
{
style.BackgroundColor("green");
});
});
});
In the example above only the window player receives the updated panel. In case you want to update the panel for all players at once you may want to call the Update method on the UI instance
root.Panel("my_panel_id", panel =>
{
panel.Style.BackgroundColor("red");
});
root.Button(button =>
{
button.OnClick(Event =>
{
// this will update the panel for all players viewing this UI
Event.UI.Update("my_panel_id", (style) =>
{
style.BackgroundColor("green");
});
});
});
Refreshing Elements
Just like updating elements, elements that needs to receive a refresh require to have set an ID. Where updating elements only update the style of the element triggers a refresh a full element re-render
bool HasError = false;
root.Panel("my_panel_id", panel =>
{
if(HasError)
{
panel.Style.SetBackgroundColor(UIColor.Red700);
panel.Label(label =>
{
label.Style.SetText("An Error Occured!")
.SetFontColor(UIColor.Red100);
});
return;
}
panel.Style.SetBackgroundColor(UIColor.Neutral100);
});
root.Button(button =>
{
button.OnClick(Event =>
{
HasError = true;
Event.Window.Refresh("my_panel_id");
});
});
Trigger Element Actions
RustUI alows you to replace the default action for an element. For example, you have build a menu with buttons and when a player clicks a button in the menu you want to trigger a action in a panel that acts like a IFRAME. This allows you to define a single panel element that dynamically changes content.
root.Panel("content_frame", panel =>
{
panel.Label(label =>
{
label.Style.SetText("This is default content!");
});
});
root.Button(button =>
{
button.OnClick(Event =>
{
Event.Window.Action<ElementPanel>("content_frame", (panel) =>
{
panel.Label(label =>
{
label.Style.SetText("This is the Rules page!");
});
});
});
});
root.Button(button =>
{
button.OnClick(Event =>
{
Event.Window.Action<ElementPanel>("content_frame", (panel) =>
{
panel.Label(label =>
{
label.Style.SetText("This is the contact page!");
});
});
});
});
root.Button(button =>
{
button.OnClick(Event =>
{
// to prevent a bloating UI with tons of actions you could set a plugin method as the callback
Event.Window.Action<ElementPanel>("content_frame", ShowSomeOtherPage});
});
});
Introduction to CUI Elements
RustUI offers pre-defined elements matching the native Oxide elements stack that you can use to build your UI. Every element expects a lambda closure that receives exactly 1 argument
(element)
{
//
}
You can use the element to:
-
Nest child elements
root.Panel(panelElement => { // nest a label inside the panel "element" panelElement.Label(labelElement => { }) }); -
Access the
Styleobjectroot.Panel(panelElement => { panelElement.Style.SetWidth("400px"); }); -
Access the
Windowobjectroot.Label(label => { label.Style.SetText($"Hello, {label.Window.Player.displayName}"); });
Giving elements an ID
By default every element gets a unique ID behind the scenes, but you may want to assign an ID yourself to identify the element you want to update or refresh.
You can achieve this by calling the Id() method on the element:
root.Label("my_label_id", label =>
{
});
After you assigned the label ID, the label is ready to get updated or refreshed:
string labelText = "Label is sad :(";
root.Label("my_label_id", label =>
{
label.Style.SetText(labelText)
});
root.Button(button =>
{
button.OnClick(Event =>
{
labelText = "Label is happy :D";
// refresh the label
window.Refresh("my_label_id");
});
});
Panel
The panel element acts as a container and is able to accept child elements
root.Panel(panel =>
{
panel.Style.SetWidth("600px")
.SetHeight("400px");
});
Label
The label element is a text element, unlike the panel element the label element does not accept child elements
root.Label(label =>
{
label.Style.SetText("Hello World!");
});
Textfield
Just like the button element, the textfield element is also a interactable element, But it does not accept child elements
root.Textfield(textfield =>
{
textfield.Style.SetAutoFocus(true)
.SetCharsLimit(30)
.SetIsPassword(false);
});
Handle change events
A textfield is interactable, you can assign a lambda closure to capture and handle the event when the input changes
root.Textfield(textfield =>
{
textfield.Style.SetAutoFocus(true);
textfield.OnChange(changeEvent =>
{
string value = changeEvent.Payload.Get("value", "");
Puts($"{changeEvent.Player.displayName} has typed {value}");
});
});
Using the default command string
If you want use the default command string when the input changes, then do the following:
root.Textfield(textfield =>
{
textfield.Style.SetCommand("SomeCommandName");
});
Image
You can use the image element to display images, it does not accept child elements
The image element leverages the Image Library plugin so make sure it is installed on your Rust Server
In-Game Rust Item image
Simply pass the shortname of the In-Game Rust Item
root.Image(image =>
{
image.Style.SetImageSource("rifle.ak");
// optional skin id
image.Style.SetSkinId(3764289135);
});
In-Game Rust Assets
If you want to display a Rust asset then pass the assets/*.png path to the image
root.Image(image =>
{
image.Style.SetImageSource("assets/icons/fun.png");
});
Steam Image
You can do the following when you want to display a steam image for a player
root.Image(image =>
{
image.Style.SetImageSource($"steam://{window.Player.userID}");
});
Image from a URL
To display an image from an external url then all you have to do is pass the url to the image
root.Image(image =>
{
image.Style.SetImageSource($"https://www.iconsdb.com/icons/download/white/happy-64.png");
});
Controlling image blending
You may want to control the blending of an image
root.Image(image =>
{
// make the image blend to red
image.Style.SetImageBlend("red");
});
Scroller
The scroller element gives you the ability to scroll when the child elements exceeds the dimensions of the viewport, it does accept child elements
panel.Scroller(scroller =>
{
scroller.Style.SetScrollHandleColor(Theme.Primary.Darken(60))
.SetScrollTrackColor(Theme.Primary.Darken(70))
.SetHoverColor(Theme.Primary.Darken(55))
.SetPressedColor(Theme.Primary.Darken(55));
scroller.Panel(panel =>
{
panel.Style.SetHeight("2000px");
});
});
ScrollHeight
The scroller element tries to detect the scrollheight automatically, but if for some reason the scroller is not able to calculate the scrollheight correctly then you can set the scrollheight mannually
panel.Scroller(scroller =>
{
scroller.Style.SetScrollHeight("2000px");
scroller.Panel(panel =>
{
panel.Style.SetHeight("2000px");
});
});
FlexRow
The FlexRow element distributes flex items horizontally. Flex items are all equally width and height.
// create a flex row with 3 panels that are all distributed from left to right
root.FlexRow((row) =>
{
row.Panel(panel => {
});
row.Panel(panel => {
});
row.Panel(panel => {
});
});
Setting flex item width
You can adjust the width of a flex item individually. In the example below we set the width of the second flex item to 60%, flex items on the left and right will span the remaining width of the viewport equally
root.FlexRow((row) =>
{
row.Panel(panel =>
{
// spans 20% of the remaining width
});
row.Panel(panel =>
{
panel.Style.SetWidth("60%");
});
row.Panel(panel =>
{
// spans 20% of the remaining width
});
});
Flex Gap
You can tell the FlexRow how much space there should be between the flex items by setting the FlexGap property
root.FlexRow(row =>
{
row.Style.SetFlexGap("10px");
});
Flex Reverse
You can inverse the order of the flex items by setting the FlexReverse property
root.FlexRow(row =>
{
row.Style.SetFlexReverse(true);
});
Combining the FlexReverse property with a Button element
bool FlexReverse = false;
root.FlexRow("example_flex_row", row =>
{
row.Style.SetFlexReverse(FlexReverse);
row.Panel(panel =>
{
panel.Style.SetBackgroundColor("red");
});
row.Panel(panel =>
{
panel.Style.SetBackgroundColor("green");
});
row.Panel(panel =>
{
panel.Style.SetBackgroundColor("blue");
});
});
root.Button(button =>
{
button.Style.SetText("Toggle Flex Reverse");
button.OnClick(clickEvent =>
{
FlexReverse = !FlexReverse;
clickEvent.Window.Refresh("example_flex_row");
});
});
Or instead of using a bool FlexReverse variable you could use the FlexReverse property on the element itself
row.Style.SetFlexReverse(!row.Style.FlexReverse);
FlexColumn
The FlexColumn element has the same purpose as FlexRow but a FlexColumn distributes flex items vertically. Flex items are all equally width and height.
// create a flex column with 3 panels that are all distributed from top to bottom
root.FlexColumn(column =>
{
column.Panel(panel => {
});
column.Panel(panel => {
});
column.Panel(panel => {
});
});
Setting flex item height
You can adjust the height of a flex item individually. In the example below we set the height of the second flex item to 60%, flex items above and below will span the remaining height of the viewport equally
root.FlexColumn((column) =>
{
column.Panel(panel =>
{
// spans 20% of the remaining height
});
column.Panel(panel =>
{
panel.Style.SetHeight("60%");
});
column.Panel(panel =>
{
// spans 20% of the remaining height
});
});
Flex Gap
You can tell the FlexRow how much space there should be between the flex items by setting the FlexGap property
root.FlexColumn(row =>
{
row.Style.SetFlexGap("10px");
});
Flex Reverse
You can inverse the order of the flex items by setting the FlexReverse property
root.FlexColumn(row =>
{
row.Style.SetFlexReverse(true);
});
Combining the FlexReverse property with a Button element
bool FlexReverse = false;
root.FlexColumn("example_flex_column", column =>
{
column.Style.SetFlexReverse(FlexReverse);
column.Panel(panel =>
{
panel.Style.SetBackgroundColor("red");
});
column.Panel(panel =>
{
panel.Style.SetBackgroundColor("green");
});
column.Panel(panel =>
{
panel.Style.SetBackgroundColor("blue");
});
});
root.Button(button =>
{
button.Style.SetText("Toggle Flex Reverse");
button.OnClick(clickEvent =>
{
FlexReverse = !FlexReverse;
clickEvent.Window.Refresh("example_flex_column");
});
});
Or instead of using a bool FlexReverse variable you could use the FlexReverse property on the element itself
column.Style.SetFlexReverse(!column.Style.FlexReverse);
Bringing it all together
By combining FlexRow and FlexColumn elements you are able to create practically any template you can think of! Lets create a 3x3 grid using only Flex elements
root.FlexColumn((column) =>
{
column.Style.SetFlexGap("10px");
column.FlexRow(row =>
{
row.Style.SetFlexGap("10px");
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 1"));
});
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 2"));
});
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 3"));
});
});
column.FlexRow(row =>
{
row.Style.SetFlexGap("10px");
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 4"));
});
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 5"));
});
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 6"));
});
});
column.FlexRow(row =>
{
row.Style.SetFlexGap("10px");
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 7"));
});
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 8"));
});
row.Panel(panel =>
{
panel.Label(label => label.Style.SetText("Item 9"));
});
});
});
Or use the build-in GridView component
root.Component<GridView<string>>(component =>
{
component.GridId = "grid_example";
component.UseScroll = false;
component.ItemsPerRow = 3;
component.FlexGap = 10f;
component.Items = new List<string>(){"1", "2", "3", "4", "5", "6", "7", "8", "9"};
component.ItemAction = (container, item) =>
{
container.Label(label =>
{
label.Style.SetText($"Item {item}")
});
}
});
Custom
The Custom element allows you to mannually pass Oxide CUI Components and compose the element as you like. RustUI will take care of the element position and size like any other element.
using Oxide.Game.Rust.Cui;
panel.Custom(custom =>
{
custom.Components.Add(new CuiOutlineComponent
{
Color = "0 0 0 1",
Distance = "2 2",
UseGraphicAlpha = false
});
});
Custom elements also supports nesting child elements like all container elements
using Oxide.Game.Rust.Cui;
panel.Custom(custom =>
{
custom.Components.Add(new CuiOutlineComponent
{
Color = "0 0 0 1",
Distance = "2 2",
UseGraphicAlpha = false
});
custom.Image(image =>
{
image.Style.SetImageSource("rifle.ak");
});
});
Element Styles
Every element in RustUI has a Style property that you can use to style or configure the element. All of these methods may be chained to fluently manipulate the underlying Style object. You can find every style option in the list below.
Available Styles
Autofocus
Sets or gets the autofocus of the textfield
// setters
element.Style.SetAutofocus(false);
// getter
bool value = element.Style.Autofocus;
AutoScrollHeight
Sets or gets if scroll height should automatically get calculated
// setter
element.Style.SetAutoScrollHeight(true);
// getter
bool value = element.Style.AutoScrollHeight;
BackgroundColor
Sets or gets the background color
// setter
element.Style.SetBackgroundColor("black");
// getter
UIColor value = element.Style.BackgroundColor;
BackgroundImage
Sets or gets the background image of a panel, this can be set to an material, sprite, icon, rust item or external images
// setter
element.Style.SetBackgroundImage(Materials.Binocular);
// or and external image
element.Style.SetBackgroundImage("https://example.com/image.png");
// or a sprite
element.Style.SetBackgroundImage(Sprites.SkewedGradient);
// getter
UIColor value = element.Style.BackgroundImage;
Border
Sets multiple borders at once
// setter per side
element.Style.SetBorder(top: "10px", right: "10px", bottom: "10px", left: "10px");
// setter all at once
element.Style.SetBorder("10px");
BorderBottom
Sets or gets the bottom border
// setter
element.Style.SetBorderBottom("10px");
// getter
LayoutValue value = element.Style.BorderBottom;
BorderBottomColor
Sets or gets the bottom border color
// setter
element.Style.SetBorderBottomColor(Theme.Primary);
// getter
UIColor value = element.Style.BorderBottomColor;
BorderColor
Sets multiple border colors at once
// setter per side
element.Style.SetBorder(top: UIColor.Zinc500, right: UIColor.Zinc600, bottom: UIColor.Zinc700, left: UIColor.Zinc800);
// setter all at once
element.Style.SetBorder(Theme.Secondary.Lighten(10f));
BorderLeft
Sets or gets the left border
// setter
element.Style.SetBorderLeft("10px");
// getter
LayoutValue value = element.Style.BorderLeft;
BorderLeftColor
Sets or gets the left border color
// setter
element.Style.SetBorderLeftColor(Theme.Secondary);
// getter
UIColor value = element.Style.BorderLeftColor;
BorderRight
Sets or gets the right border
// setter
element.Style.SetBorderRight("10px");
// getter
LayoutValue value = element.Style.BorderRight;
BorderRightColor
Sets or gets the right border color
// setter
element.Style.SetBorderRightColor(UIColor.Zinc500);
// getter
UIColor value = element.Style.BorderRightColor;
BorderTop
Sets or gets the top border
// setter
element.Style.SetBorderTop("100px");
// getter
LayoutValue value = element.Style.BorderTop;
BorderTopColor
Sets or gets the top border color
// setter
element.Style.SetBorderTopColor("black");
// getter
UIColor value = element.Style.BorderTopColor;
Bottom
Sets or gets the bottom offset
// setter
element.Style.SetBottom("10px");
// getter
LayoutValue value = element.Style.Bottom;
BoxShadowColor
Sets or gets the color of the box shadow
// setters
element.Style.SetBoxShadowColor(UIColor.Zinc800.SetAlpha(80f));
// getter
UIColor value = element.Style.BoxShadowColor;
BoxShadowPosition
Sets or gets the position of the box shadow
// setters
element.Style.SetBoxShadowPosition("1 1");
// getter
string value = element.Style.BoxShadowPosition;
CharsLimit
Sets or gets the max chars of the textfield
// setters
element.Style.SetCharsLimit(30);
// getter
int value = element.Style.CharsLimit;
ColorMultiplier
Sets or gets the color multiplier (applies to the button element)
// setter
element.Style.SetColorMultiplier(1f);
// getter
float? value = element.Style.ColorMultiplier;
Command
Sets or gets the command that should get executed (buttons and textfields)
// setters
element.Style.SetCommand("chat.say /kits");
// getter
string value = element.Style.Command;
CursorEnabled
Enables or disables the cursor in the UI
// setter
element.Style.SetCursorEnabled(true);
// getter
bool value = element.Style.CursorEnabled;
Disabled
Sets or gets if the element is disabled or enabled
// setter
element.Style.SetDisabled(false);
// getter
bool value = element.Style.Disabled;
DisabledColor
Sets or gets the color when the element is disabled
// setters
element.Style.SetDisabledColor(UIColor.Neutral400);
// getter
UIColor value = element.Style.DisabledColor;
FadeIn
Sets or gets the duration the element should fadeIn
// setters
element.Style.SetFadeIn(1f);
// getter
float value = element.Style.FadeIn;
FadeOut
Sets or gets the duration the element should fadeOut
// setters
element.Style.SetFadeOut(1f);
// getter
float value = element.Style.FadeOut;
FlexDirection
Sets or gets the direction of the flex container
// setters
element.Style.SetFlexDirection("row");
element.Style.SetFlexDirection("column");
// getter
string value = element.Style.FlexDirection;
FlexGap
Sets or gets the gap between flex items
// setters
element.Style.SetFlexGap("10px");
// getter
LayoutValue? value = element.Style.FlexGap;
FlexReverse
Sets or gets the order of the flex items
// setters
element.Style.SetFlexReverse(false);
// getter
bool value = element.Style.FlexReverse;
FontColor
Sets or gets the font color
// setter
element.Style.SetFontColor("black");
// getter
UIColor value = element.Style.FontColor;
FontFamily
Sets or gets the font family
// setters
element.Style.SetFontFamily("RobotoCondensed-Bold.ttf");
element.Style.SetFontFamily("DroidSansMono.ttf");
element.Style.SetFontFamily("PermanentMarker.ttf");
element.Style.SetFontFamily("RobotoCondensed-Regular.ttf"); // default
// getter
string value = element.Style.FontFamily;
FontSize
Sets or gets the font size
// setter
element.Style.SetFontSize(14);
// getter
int value = element.Style.FontSize;
Height
Sets or gets the height
// setter
element.Style.SetHeight("100px");
// getter
LayoutValue value = element.Style.Height;
HoverColor
Sets or gets the color when hovering over a button or scrollhandle
// setters
element.Style.SetHoverColor(Theme.Primary.Lighten(5f));
// getter
UIColor value = element.Style.HoverColor;
ImageSource
Sets or gets the image source
// setters
element.Style.SetImageSource("rifle.ak");
// getter
string value = element.Style.ImageSource;
ImageBlend
Sets or gets the blending of the image
// setters
element.Style.SetImageBlend(Theme.Primary.SetAlpha(0.5f));
// getter
string value = element.Style.ImageBlend;
ImageType
Sets or gets the image type for images
// setters
element.Style.SetImageType(UnityEngine.UI.Image.Type.Filled);
element.Style.SetImageType(UnityEngine.UI.Image.Type.Tiled);
element.Style.SetImageType(UnityEngine.UI.Image.Type.Sliced);
element.Style.SetImageType(UnityEngine.UI.Image.Type.Simple);
// getter
UnityEngine.UI.Image.Type value = element.Style.ImageType;
IsPassword
Sets or gets if the textfield is a password field
// setters
element.Style.SetIsPassword(false);
// getter
bool value = element.Style.IsPassword;
KeyboardEnabled
Enables or disables the player movement while the UI is open
// setter
element.Style.SetKeyboardEnabled(false);
// getter
bool value = element.Style.KeyboardEnabled;
Left
Sets or gets the left offset
// setter
element.Style.SetLeft("10px");
// getter
LayoutValue value = element.Style.Left;
LineType
Sets or gets the linetype of the textfield element
// setter
element.Style.SetTextAlign(InputField.LineType.SingleLine);
element.Style.SetTextAlign(InputField.LineType.MultiLineSubmit);
element.Style.SetTextAlign(InputField.LineType.MultiLineNewline);
// getter
InputField.LineType value = element.Style.LineType;
Offset
Sets multiple offsets at once
// setter per side
element.Style.SetOffset(top: "10px", right: "10px", bottom: "10px", left: "10px");
// setter all at once
element.Style.SetOffset("10px");
Padding
Sets multiple paddings at once
// setter per side
element.Style.SetPadding(top: "10px", right: "10px", bottom: "10px", left: "10px");
// setter all at once
element.Style.SetPadding("10px");
PaddingBottom
Sets or gets the bottom padding
// setter
element.Style.SetPaddingBottom("10px");
// getter
LayoutValue value = element.Style.PaddingBottom;
PaddingLeft
Sets or gets the left padding
// setter
element.Style.SetPaddingLeft("10px");
// getter
LayoutValue value = element.Style.PaddingLeft;
PaddingRight
Sets or gets the right padding
// setter
element.Style.SetPaddingRight("10px");
// getter
LayoutValue value = element.Style.PaddingRight;
PaddingTop
Sets or gets the top padding
// setter
element.Style.SetPaddingTop("100px");
// getter
LayoutValue value = element.Style.PaddingTop;
PressedColor
Sets or gets the color when pressing a button or scrollhandle
// setters
element.Style.SetPressedColor(Theme.Primary.Lighten(5f));
// getter
UIColor value = element.Style.PressedColor;
ReadOnly
Sets or gets if the textfield is a readonly textfield
// setters
element.Style.SetReadOnly(false);
// getter
bool value = element.Style.ReadOnly;
Right
Sets or gets the right offset
// setter
element.Style.SetRight("10px");
// getter
LayoutValue value = element.Style.Right;
ScrollHeight
Sets or gets a forced scroll height
// setter
element.Style.SetScrollHeight("2000px");
// getter
LayoutValue value = element.Style.ScrollHeight;
ScrollHandleColor
Sets or gets the color of the scroll handle
// setters
element.Style.SetScrollHandleColor(UIColor.Zinc800);
// getter
UIColor value = element.Style.ScrollHandleColor;
ScrollHandleWidth
Sets or gets the with of the scroll handle
// setters
element.Style.SetScrollHandleWidth(8);
// getter
int value = element.Style.ScrollHandleWidth;
ScrollTrackColor
Sets or gets the color of the scroll track
// setters
element.Style.SetScrollTrackColor(UIColor.Zinc500);
// getter
UIColor value = element.Style.ScrollTrackColor;
SkinId
Sets or gets the skinID of the image (shortnamed images)
// setters
element.Style.SetSkinId(3764289135);
// getter
ulong value = element.Style.SkinId;
Text
Sets or gets the text in a label or button
// setter
element.Style.SetText("Hello World!");
// getter
string value = element.Style.Text;
TextAlign
Sets or gets the text alignment
// setters
element.Style.SetTextAlign(TextAnchor.UpperLeft);
element.Style.SetTextAlign(TextAnchor.UpperCenter);
element.Style.SetTextAlign(TextAnchor.UpperRight);
element.Style.SetTextAlign(TextAnchor.MiddleLeft);
element.Style.SetTextAlign(TextAnchor.MiddleCenter);
element.Style.SetTextAlign(TextAnchor.MiddleRight);
element.Style.SetTextAlign(TextAnchor.LowerLeft);
element.Style.SetTextAlign(TextAnchor.LowerCenter);
element.Style.SetTextAlign(TextAnchor.LowerRight);
// getter
TextAnchor value = element.Style.TextAlign;
TextShadowColor
Sets or gets the text shadow (outline)
// setters
element.Style.SetTextShadowColor("0 0 0 0.5");
// getter
UIColor value = element.Style.TextShadowColor;
TextShadowPosition
Sets or gets the position of the text shadow (outline)
// setters
element.Style.SetTextShadowPosition("1 1");
// getter
string value = element.Style.TextShadowPosition;
TextWrap
Sets or gets the text wrap of the label element
// setters
element.Style.SetTextWrap(VerticalWrapMode.Truncate);
element.Style.SetTextWrap(VerticalWrapMode.Overflow);
// getter
VerticalWrapMode value = element.Style.TextWrap;
TooltipDelay
Sets or gets the duration on how long the tooltip stays visible
// setters
element.Style.SetTooltipDelay(Tooltip.DelayType.Short);
element.Style.SetTooltipDelay(Tooltip.DelayType.Long);
// getter
Tooltip.DelayType value = element.Style.TooltipDelay;
TooltipEnabled
Sets or gets if the tooltip is enabled
// setters
element.Style.SetTooltipEnabled(true);
// getter
bool value = element.Style.TooltipEnabled;
TooltipPosition
Sets or gets the position of the tooltip
// setters
element.Style.SetTooltipPosition(TooltipContainer.PositionMode.Auto);
element.Style.SetTooltipPosition(TooltipContainer.PositionMode.Top);
element.Style.SetTooltipPosition(TooltipContainer.PositionMode.Bottom);
element.Style.SetTooltipPosition(TooltipContainer.PositionMode.Left);
element.Style.SetTooltipPosition(TooltipContainer.PositionMode.Right);
element.Style.SetTooltipPosition(TooltipContainer.PositionMode.TopLeft);
// getter
TooltipContainer.PositionMode value = element.Style.TooltipPosition;
TooltipText
Sets or gets the text of a tooltip when a player hovers over de element
// setters
element.Style.SetTooltipText("Hello World!");
// getter
string value = element.Style.TooltipText;
TooltipType
Sets or gets the tooltip type
// setters
element.Style.SetTooltipDelay(CommunityEntity.TooltipType.Default);
element.Style.SetTooltipDelay(CommunityEntity.TooltipType.AlwaysOnTop);
element.Style.SetTooltipDelay(CommunityEntity.TooltipType.AlwaysOnTopEmoji);
// getter
CommunityEntity.TooltipType value = element.Style.TooltipType;
TooltipUseCentre
Sets or gets the if the text of the tooltip should get centered
// setters
element.Style.SetTooltipUseCentre(true);
// getter
bool value = element.Style.TooltipUseCentre;
Top
Sets or gets the top offset
// setter
element.Style.SetTop("100px");
// getter
LayoutValue value = element.Style.Top;
Width
Sets or gets the width
// setter
element.Style.SetWidth("100px");
// getter
LayoutValue value = element.Style.Width;
Themes
RustUI lets you style your interfaces using a dedicated theme engine.
Instead of hardcoding colors, margins, and sizes on every single button or panel, the framework uses a straightforward CSS-like approach. This means you can write clean, reusable stylesheet rules using selectors you already know, such as classes, IDs, child relations, and even pseudo-states. It completely separates your layout structure from your styling, keeping your plugin code organized and much easier to maintain as your project grows.
Writing your stylesheets feels just like writing traditional CSS, wrapped in a clean, fluent C# API:
// Matches every "ElementButton" element
Theme.Css("ElementButton", style =>
{
style.SetWidth("120px")
.SetHeight("40px")
.SetBackgroundColor(UIColor.Gray700)
.SetHoverColor(UIColor.Gray600);
});
// Matches every "ElementButton" element inside a parent with a "dashboard_panel" ID
Theme.Css("#dashboard_panel ElementButton", style =>
{
style.SetBackgroundColor(UIColor.Cyan600);
});
// Matches the element with "submit_btn" ID that has a disabled state
Theme.Css("#submit_btn:disabled", style =>
{
style.SetBackgroundColor(UIColor.Gray500);
});
// Matches every "odd" element with class "item" nested inside the "GridView" component
Theme.Css("ComponentPanel.GridView .item:nth-child(odd)", style =>
{
style.SetBackgroundColor("#1e1e1e");
});
Available Selectors
-
ElementType
Matches elements based on their exact
Elementclass name or any base class they inherit from (e.g., ElementButton or PanelElement). -
.class
Matches any element that contains the specified class name.
-
#id
Matches the unique element whose Id() method exactly matches the specified ID string.
-
.class1.class2
Matches a single element that possesses all consecutive class names simultaneously (Compound Selector).
-
#id.class
Matches a specific element based on its unique ID, but only if the element currently possesses the specified class name as well.
-
ComponentPanel.ComponentType
Matches your custom RustUI component wrappers by inspecting whether the internal Component type matches the ComponentType (supports generic classes like GridView).
-
selector, selector
Allows applying the same style rules to multiple independent target selectors separated by commas.
-
selector selector
Matches an element that is deeply nested anywhere inside (as a descendant of) a specific ancestor element (Descendant Selector).
-
selector > selector
Matches an element only if it is a direct and immediate child of the specified parent element (Child Selector).
-
selector + selector
Matches an element only if it is a adjacent of the specified element (Right Sibling).
-
:disabled
Matches elements that have their Style.Disabled state set to true. This rule is automatically given extra specificity weight.
-
:first-child
Matches an element only if it occupies the very first position (Index() == 0) within its parent's children list.
-
:last-child
Matches an element only if it occupies the absolute last position within its parent's children list.
-
:only-child
Matches an element if it is the sole and only child element contained within its parent's list.
-
:nth-child(even)
Matches all elements occupying an even numerical position (2, 4, 6, etc.) within their parent, ideal for zebra-striping grids.
-
:nth-child(odd)
Matches all elements occupying an odd numerical position (1, 3, 5, etc.) within their parent.
-
:nth-child(number)
Matches an element occupying an exact, specific index position within its parent (e.g., :nth-child(3) for the third element).
-
:not(selector)
Negates the matching logic; applies styles to the element only if it does NOT satisfy the selector conditions inside the parentheses (e.g., :not(.active)).
-
:is(selector)
Applies styles to the element only if it does satisfy the selector conditions inside the parentheses (e.g., :is(.active)).
-
:has(selector)
Applies styles to the parent element only if at least one of its child or descendant elements satisfies the selector conditions inside the parentheses (e.g., .card:has(ElementImage)).
Creating A Theme
Lets define a basic theme:
Theme.Primary = UIColor.Cyan600;
Theme.Secondary = UIColor.LightGreen;
Theme.Background = Theme.Primary.Darken(percent: 50f, alpha: 0.5f);
Theme.FontColor = Theme.Primary.Lighten(percent: 80f, alpha: 0.8f);
Theme.Css(".my-panel", style =>
{
style.SetBackgroundColor(Theme.Background);
});
Theming Elements
RustUI also offers you the option to theme basic elements like buttons, textfield and labels. After you applied the default theme styles on your elements will inherit these style when you create the element inside your UI.
Theme.Primary = UIColor.Cyan600;
Theme.Secondary = UIColor.LightGreen;
Theme.Background = Theme.Primary.Darken(percent: 50f, alpha: 0.5f);
Theme.FontColor = Theme.Primary.Lighten(percent: 80f, alpha: 0.8f);
Theme.Css("ElementButton", (style) =>
{
style.SetBackgroundColor(Primary)
.SetHoverColor(Theme.Primary.Lighten(20f))
.SetMaterial(Materials.Binocular)
.SetBorderColor(Theme.Primary.Darken(20f))
.SetBorder("0px");
});
Theme.Css("ElementButton.secondary", (style) =>
{
style.SetBackgroundColor(Theme.Secondary)
.SetHoverColor(Theme.Secondary.Lighten(20f))
.SetBorderColor(Theme.Secondary.Darken(20f));
});
Theme.Css("ElementButton.success", (style) =>
{
style.SetBackgroundColor(Theme.Success)
.SetHoverColor(Theme.Success.Lighten(20f))
.SetBorderColor(Theme.Success.Darken(20f));
});
Theme.Css("ElementButton.danger", (style) =>
{
style.SetBackgroundColor(Theme.Danger)
.SetHoverColor(Theme.Danger.Lighten(20f))
.SetBorderColor(Theme.Danger.Darken(20f));
});
Theme.Css("ElementButton.warning", (style) =>
{
style.SetBackgroundColor(Theme.Warning)
.SetHoverColor(Theme.Warning.Lighten(20f))
.SetBorderColor(Theme.Warning.Darken(20f));
});
Theme.Css("ElementButton.info", (style) =>
{
style.SetBackgroundColor(Theme.Info)
.SetHoverColor(Theme.Info.Lighten(20f))
.SetBorderColor(Theme.Info.Darken(20f));
});
Theme.Css("ElementScroller", (style) =>
{
style.SetScrollHandleColor(Theme.Primary.Darken(60))
.SetScrollTrackColor(Theme.Primary.Darken(70))
.SetHoverColor(Theme.Primary.Darken(55))
.SetPressedColor(Theme.Primary.Darken(55));
});
UI Colors
The UIColor object provides an expressive, fluid interface for accessing the most commonly used colors in modern UI design. Out of the box, it arms your application with a beautiful, comprehensive palette right at your fingertips. Beyond basic values, UIColor instances unlock powerful color-manipulation capabilities. You may chain fluent methods such as Darken() and Lighten() directly onto any defined color.
Lighten a color
element.Style.SetBackgroundColor(UIColor.Cyan900.Lighten(20f));
Darken a color
element.Style.SetBackgroundColor(UIColor.Cyan900.Darken(percent: 20f));
Applying Alpha
element.Style.SetBackgroundColor(UIColor.Cyan900.Darken(percent: 20f, alpha: 0.5f));
// or use the SetAlpha method
element.Style.SetBackgroundColor(UIColor.Cyan900.SetAlpha(0.5f));
Named Colors
The UIColor object gives you the option to define a color by name, hex, rgba and Rust format
// named
element.Style.SetBackgroundColor("cyan900");
// hex
element.Style.SetBackgroundColor("#164e63");
// rgb
element.Style.SetBackgroundColor("rgba(22,78,99)");
// rgba
element.Style.SetBackgroundColor("rgba(22,78,99,1)");
// hsl
element.Style.SetBackgroundColor("hsl(196,64%,24%)");
// rust
element.Style.SetBackgroundColor("0.08627 0.30588 0.38824 1.0");
Available Colors
Simply click any color block to copy its signature to your clipboard.
Components
RustUI gives you the ability to theme your UI. You can create multiple themes and bind a theme to individual UI's.
Core Components
Components allows you to inject powerful reusable functionality in to your UI. Below you will find a list of core components:
CloseButton
This component can be used to display a button that closes the UI
Configuration Options
-
string Size
The size of the button inpxor% -
OnClick(Action<UIEvent> Event)
Override the default click event
root.Component<CloseButton>(component = >
{
component.Size = "30px";
});
By default this component will close the UI, if you wish you can override the OnClick event
root.Component<CloseButton>(component = >
{
component.Size = "30px";
component.OnClick(Event =>
{
ShowOverlay = false;
Event.Window.Refresh("overlay_element");
});
});
You can style the CloseButton component like so:
Theme.Css("ComponentPanel.CloseButton ElementButton", (style) =>
{
style.SetBackgroundColor(UIColor.Amber500);
});
GridView
This component renders a flex grid.
Configuration Options
-
string GridId
The ID for this grid -
bool UseScroll
true or false if the component should scroll when the content overflows the parent -
int ItemsPerRow
How many flex items the grid should render per row -
string FlexGap
Distance between the flex items -
float ItemHeight
The height of the item container -
string EmptyGridMessage
Text to show when theItemscontains zero entries -
List<T> Items
A list with items of type (T) -
Action<ElementPanel, Item> ItemAction
A closure action for each item
root.Component<GridView<T>>((component) =>
{
component.GridId = "grid_example";
component.UseScroll = false;
component.ItemsPerRow = 3;
component.FlexGap = 10f;
component.Items = new List<string>(){"1", "2", "3", "4", "5", "6", "7", "8", "9"};
component.ItemAction = (container, item) =>
{
container.Label(label =>
{
label.Style.SetText($"Item {item}")
});
}
});
You can style the GridView component like so:
Theme.Css("ComponentPanel.GridView .item", (style) =>
{
style.SetBackgroundColor(UIColor.Amber500);
});
TimerEvery
The TimerEvery component is useful when you want to updates elements with a interval
Configuration Options
-
float Delay
The timer interval -
Slot(Action<ElementPanel>) Slot()
The slot that defines the template that should update everyDelay
root.Component<TimerEvery>(component =>
{
component.Delay = 1f;
component.Slot(panel =>
{
panel.Label(label =>
{
if (ZoneManager.IsInPVPZone(label.Window.Player))
{
label.Style.SetText("<b>PVP ZONE</b>")
.SetFontColor("red");
}
else
{
label.Style.SetText("<b>PVE ZONE</b>")
.SetFontColor("green");
}
});
});
});
Creating a Component
Creating your own components is really easy. All a component needs is a public override Action<ComponentPanel> Action() method that RustUI calls to render the template for the component. Lets create very basic component with a label that displays some text that has been set in the ComponentLabelText config option.
public class MyCustomComponent : Component<MyCustomComponent>
{
public string ComponentLabelText = "Default label text";
public MyCustomComponent( ComponentPanel panel ) : base(panel)
{
// every component requires a constructor
}
public override void OnDestroy(UIWindow window)
{
// called when the component gets destroyed
}
public override void OnReady(UIWindow window)
{
// called when the component has been initialized
}
public override Action<ComponentPanel> Action()
{
return (panel) =>
{
panel.Label(label =>
{
label.Style.SetText(ComponentLabelText);
});
};
}
}
Using the Custom Component
Now that we defined our MyCustomComponent we are ready to use it in the UI
root.Component<MyCustomComponent>(component =>
{
component.ComponentLabelText = "MyCustomComponent Works!";
});
You can even style the label inside your component
Theme.Css("ComponentPanel.MyCustomComponent ElementLabel", (style) =>
{
style.SetFontColor(Theme.Success);
});