React Clean UI
Surface

Box

A simple themed container for grouping content.

The Box component is a themed container that provides a background, border, rounded corners, padding, and shadow. It is useful for grouping related UI elements such as forms, cards, panels, or settings sections.

Example

Loom Preview

Sizing

Box supports the standard sizing props, allowing it to fill available space or use fixed dimensions.

<Box width="300px" height="200px">
    <Text text="Fixed size box" />
</Box>

Background image

Theme authors can set theme.components.box.backgroundImage to layer a 9-slice or scaled image on top of every Box's background colour. This is purely additive — backgroundColor, border-color, corner radius, and box-shadow all keep working unchanged, so it's a way to build custom visual skins (a wooden-frame box, a beveled button, etc.) without giving up the existing token-based options. The border stroke still draws on top of the image, the corner radius still clips it, and the shadow still applies outside it.

Box also accepts a background-image prop directly, which overrides the themed backgroundImage for that single instance — the same pattern used by border-color/border-thickness.

Unlike CSS's border-image-slice, slice isn't an edge inset — it's the two literal corner points of the unscaled centre region, in absolute source-image pixel coordinates (the same values you'd pass to Roblox's own SliceCenter/Rect.new(minX, minY, maxX, maxY)). Roblox has no API for deriving those coordinates from an inset alone, so picking sensible values means knowing the source image's actual pixel dimensions. The example below assumes a 128x128 source image with a 12px sharp border, so the unscaled centre region runs from (12, 12) to (116, 116):

<Box
    spacing="md"
    background-image={{
        image: "rbxassetid://1234567890",
        slice: "12 116",
    }}
>
    <Text text="Wooden Frame" variant="heading" />
</Box>

slice's coordinates are always the border's literal pixel size in the source image, so that same 12px border would otherwise render at 12px on every Box regardless of size. Add sliceScale (below 1) to shrink the rendered border thickness without touching slice itself:

<Box
    spacing="md"
    background-image={{
        image: "rbxassetid://1234567890",
        slice: "12 116",
        sliceScale: 0.5,
    }}
>
    <Text text="Thinner border" variant="heading" />
</Box>

Use createTheme (or extendTheme) to set components.box.backgroundImage theme-wide instead, then apply it to a subtree with ThemeProvider:

import { Box, createTheme, ThemeProvider, VStack, Text } from "@rbxts/react-clean-ui";

const themeWithBackgroundImage = createTheme({
    components: {
        box: {
            backgroundImage: {
                image: "rbxassetid://1234567890",
                slice: "12 116",
            },
        },
    },
});

<ThemeProvider theme={themeWithBackgroundImage}>
    <Box spacing="md">
        <VStack>
            <Text text="Wooden Frame" variant="heading" />
            <Text text="The border, corner radius, and shadow still render on top of the image." />
        </VStack>
    </Box>
</ThemeProvider>

backgroundImage accepts a CssBackgroundImage object:

FieldTypeDefaultDescription
imagestring-The rbxassetid://... image to use.
sliceCssSliceInset-Absolute pixel coordinates, within the source image, of the two corners of the unscaled centre region — matching Roblox's SliceCenter/Rect.new(minX, minY, maxX, maxY) directly. "A B" places the corners at (A, A) and (B, B) (Rect(A, A, B, B)); "A B C D" sets them independently as X1 Y1 X2 Y2 (Rect(A, B, C, D)). When set, the corners of the image stay sharp while the edges and centre stretch to fill the box. Omit for a plain, non-sliced image.
sliceScalenumber1Maps directly to ImageLabel.SliceScale. Only has an effect when slice is set. Since slice is always given in absolute source-image pixel coordinates, a source image with a large sharp-border region would otherwise always render that same large thickness on any Box; setting sliceScale below 1 shrinks the rendered border thickness proportionally, decoupling it from the slice region's literal pixel size.
sizeEnum.ScaleType | "Stretch" | "Slice" | "Tile" | "Fit" | "Crop" | Binding<Enum.ScaleType>Enum.ScaleType.StretchControls how a non-sliced image scales to fill the box. Accepts the enum, its member name as a string, or a Binding<Enum.ScaleType>. Has no effect when slice is set — the image is then always rendered 9-sliced with Enum.ScaleType.Slice.
tileSizeCssDual"100%"Size of each repeat when size resolves to Enum.ScaleType.Tile, using CSS background-size-style shorthand (e.g. "25%" for both axes, or "25% 25%" for X then Y). Has no effect otherwise, and is ignored when slice is set — slice always forces Enum.ScaleType.Slice.
transparencynumber-Transparency of the image itself, independent of BackgroundTransparency.
tintColorColor3-Colour tint applied to the image.

To tile an image instead of stretching it, pair size: Enum.ScaleType.Tile with a tileSize (e.g. "25% 25%" to repeat it 4x4 across the box):

<Box
    spacing="md"
    background-image={{
        image: "rbxassetid://1234567890",
        size: Enum.ScaleType.Tile,
        tileSize: "25% 25%",
    }}
>
    <Text text="Tiled pattern" variant="heading" />
</Box>

Background gradient

Theme authors can set theme.components.box.backgroundGradient to layer a UIGradient on top of every Box's background colour. Like backgroundImage, this is purely additive — backgroundColor, border-color, corner radius, and box-shadow all keep working unchanged, and the gradient renders underneath the border stroke and inside the clipped corner radius.

Box also accepts a background-gradient prop directly, which overrides the themed backgroundGradient for that single instance — the same pattern used by background-image.

<Box
    spacing="md"
    background-gradient={{
        colors: [Color3.fromHex("#4F46E5"), Color3.fromHex("#EC4899")],
        rotation: 45,
    }}
>
    <Text text="Gradient Box" variant="heading" />
</Box>

Use createTheme (or extendTheme) to set components.box.backgroundGradient theme-wide instead, then apply it to a subtree with ThemeProvider:

import { Box, createTheme, ThemeProvider, VStack, Text } from "@rbxts/react-clean-ui";

const themeWithBackgroundGradient = createTheme({
    components: {
        box: {
            backgroundGradient: {
                colors: [Color3.fromHex("#4F46E5"), Color3.fromHex("#EC4899")],
                rotation: 45,
            },
        },
    },
});

<ThemeProvider theme={themeWithBackgroundGradient}>
    <Box spacing="md">
        <VStack>
            <Text text="Gradient Box" variant="heading" />
            <Text text="The border, corner radius, and shadow still render on top of the gradient." />
        </VStack>
    </Box>
</ThemeProvider>

backgroundGradient accepts a CssBackgroundGradient object:

FieldTypeDefaultDescription
colorsColor3[] | ColorSequence-A plain Color3[] is spaced evenly across 0–1 (first colour at 0, last at 1). Pass a raw ColorSequence instead for full manual control over keypoint positions.
stopsnumber[]-Optional 0–1 positions, index-matched to colors. Only used when colors is a plain array — ignored when colors is already a ColorSequence, since that already carries its own keypoint positions. Values are clamped to the 0-1 range.
rotationnumber0Degrees, maps directly to UIGradient.Rotation (0 = left→right, clockwise).
offsetVector2-Maps directly to UIGradient.Offset.
transparencynumber | NumberSequence-A single number applies uniform transparency; pass a raw NumberSequence for full control.

Props

PropTypeDescription
widthCssSizeWidth of the box.
heightCssSizeHeight of the box.
SizeUDim2Overrides width and height with an explicit Roblox size.
spacingScaleSize | "None"Controls the internal padding.
BackgroundColor3Color3Overrides the themed background colour.
BackgroundTransparencynumberOverrides the themed background transparency.
box-shadowCssShadowOverrides the default shadow.
border-thicknessnumberOverrides the themed border thickness.
border-colorColor3Overrides the themed border colour.
background-imageCssBackgroundImageOverrides the themed background image for this instance.
background-gradientCssBackgroundGradientOverrides the themed background gradient for this instance.
ZIndexnumberSets the rendering order.

Notes

  • Uses the current theme for colours, border, corner radius, shadow, padding, and (optionally) background image.
  • Automatically sizes vertically to fit its children.
  • Accepts any child components.
GitHub Repository

On this page