s&box
RustCounter-Strike 2s&boxDeadlock
Wiki
Get s&box on Steam
Browse
OverviewGetting StartedCreating GamesEngine & ToolsDocumentationCommunity GamesResources
s&boxDocumentationUiRazor PanelsRazor Components
SOURCE 2 · C#
Build and play games with s&box.

Facepunch's game engine and creation platform — make games in C#, or jump straight into community games.

Get s&box on Steam

s&box Wiki

  • Overview
  • Getting Started
  • Creating Games
  • Engine & Tools
  • Documentation
  • Community Games
  • Resources

Tools & Community

  • Getting Started
  • Creating Games
  • Engine & Tools
  • Resources

Platforms

  • RustBattle
  • CSBattle
  • Rust Game Wiki
  • CS2 Skins Wiki
  • Deadlock Wiki

About

  • Official Site
  • Developer Wiki
  • GitHub
  • Get on Steam
NOT AFFILIATED WITH FACEPUNCH STUDIOS · © 2026 s&box Wiki (community)
Docs/UI
UI

Razor Components

Razor Component allow you to define some content to show inside another razor file. This makes it easy to create Panels that are more agile and reusable.

Here's an example called InfoCard.razor:

<root>
    <div class="header">@Header</div>
    <div class="body">@Body</div>
    <div class="footer">@Footer</div>
</root>

@code
{
    public RenderFragment Header { get; set; }
    public RenderFragment Body { get; set; }
    public RenderFragment Footer { get; set; }
}

We can now very quickly and easily create Info Cards, and even add events/functions that interact with the parent Panel:

<root>
	<InfoCard>
        <Header>My Card</Header>
        <Body>
            <div class="title">This is my card</div>
        </Body>
        <Footer>
            <div class="button" onclick="@CloseCard">Close Card</div>
        </Footer>
    </InfoCard>
</root>

@code 
{
    void CloseCard()
    {
        Delete();
    }
}

All Panels have a render fragment called ChildContent, so you can add elements inside of any Panel without adding your own fragments:

<InfoCard>
  <ChildContent>
    <label>Something inside of InfoCard</label>
  </ChildContent>
</InfoCard>

RenderFragment<T> is used to define a fragment that takes an argument. Here's PlayerList.razor:

@using Sandbox;

<root>
    @foreach ( var player in PlayerList )
    {
        <div class="row">
            @PlayerRow( player )
        </div>
    }
</root>

@code
{
    public List<Player> PlayerList { get; set; }
    public RenderFragment<Player> PlayerRow { get; set; }
}

As you can see, we're now defining PlayerRow which takes an argument. To call it we just call it like a function, with the Player argument.

Now to use it we do this:

@using Sandbox;

<root>
    <PlayerList PlayerList=@MyPlayerList>
        <PlayerRow Context="item">
            @if (item is not Player player)
                return;

            <div class="row">@player.Name</div>
            <div class="row">@player.Health</div>
        </PlayerRow>
    </PlayerList>
</root>

@code 
{
    List<Player> MyPlayerList;
}

In the PlayerRow, we add the special attribute Context, which tells our code generator that this is going to need a special object context.

Then in the fragment, we can convert this object into our target type. Then you're free to use it as you wish.

You can make a generic Panel class by using @typeparam to define the name of the parameter

@typeparam T

<root>
    This is my class for @Value
</root>

@code
{
    public T Value { get; set; }
}

You will then be able to use this like a regular generics class in C#, like PanelName<string> etc.

In Razor, you will need to add a T attribute to define the type like so:

<root>
	<MyPanel T="string"></MyPanel>
</root>

Source: Facepunch/sbox-docs (CC-BY-4.0) · updated 2025-08-29. Read it rendered on the official docs.

More in UI

HudPainter
Localization
Razor Panels
Style Properties
Styling Panels
UI
UI Interactions
VirtualGrid
← All documentation

Community wiki — not affiliated with Facepunch Studios. For the latest and most authoritative information, see the official developer wiki.