React Clean UI
Typography

Text

Display themed, auto-sizing text using the active theme's typography scale.

Text is a themed wrapper around Roblox's native TextLabel. It resolves its font, size, weight, line height, and color from the active Clean UI theme, and automatically sizes itself to fit its content.

Import

import { Text } from "@rbxts/react-clean-ui";

Basic usage

Loom Previewv0.13.2

text is the only required prop. Without a variant, the text renders using the theme's body typography style.

Variants

Use variant to select a typography style from the active theme's typography scale.

<Text text="Display" variant="display" />
<Text text="Title" variant="title" />
<Text text="Heading" variant="heading" />
<Text text="Body" variant="body" />
<Text text="Label" variant="label" />
<Text text="Caption" variant="caption" />

Each variant defines its own font, size, weight, and line height. When variant is omitted, "body" is used.

Font weight

Use weight to override the font weight defined by the variant.

<Text text="Bold text" weight="bold" />
<Text text="Extra bold text" weight={Enum.FontWeight.ExtraBold} />

The string "bold" is a shorthand for Enum.FontWeight.Bold. Without weight, the variant's own weight is used, falling back to Enum.FontWeight.Regular.

Color

Use TextColor3 to override the text color.

<Text
    text="Custom color"
    TextColor3={Color3.fromHex("#3B72E6")}
/>

By default, the text color comes from theme.colors.intents.primary.default.textColor.

Alignment

Use align to control horizontal text alignment.

<Text text="Left aligned" align="Left" />
<Text text="Center aligned" align="Center" />
<Text text="Right aligned" align="Right" />

align defaults to "Left".

Text wrapping

Long text wraps across multiple lines by default.

<Text text="Long paragraphs wrap across multiple lines by default so body copy stays readable inside narrow containers." />

Set TextWrap={false} to keep the text on a single line.

<Text
    text="This text will not wrap."
    TextWrap={false}
/>

Custom typography

Use typography to supply a complete typography style, bypassing variant entirely.

<Text
    text="Custom typography"
    typography={{
        font: Enum.Font.Gotham,
        size: Enum.FontSize.Size24,
        weight: Enum.FontWeight.Bold,
        lineHeight: 1.3,
    }}
/>

When typography is provided, variant is ignored.

Fitting text

maxWidth, outline, and shrinkToFit help text fit where it's placed: a label that wraps at a width, an outlined label over a bright background, and a letter-spaced title that shrinks into a fixed-width box.

Loom Previewv0.13.2

Min and max size

Text accepts the shared minWidth, maxWidth, minHeight, and maxHeight props (see min and max size). They render one UISizeConstraint on the label (or on the letter-spaced row).

Use maxWidth on its own for an auto-sized label that wraps at a width. A text shorter than maxWidth keeps its natural single-line size. A longer text is capped at maxWidth, wraps onto more lines, and grows in height to fit them.

<Text text="Short label" maxWidth={240} />
<Text
    text="This sentence is longer than 240 pixels, so it wraps onto a second line instead of stretching its parent."
    maxWidth={240}
/>

Wrapping must be on, which is the default. Use maxWidth instead of adding your own <uisizeconstraint> child, and don't pass both: Roblox honours only one UISizeConstraint per instance.

This works because the label's automatic size comes from its own text, which wraps (TextWrapped) at the constrained width. A maximum doesn't stop AutomaticSize growing to fit children (see min and max size). So children you pass to Text aren't capped by maxWidth, and neither is letter-spaced text.

Letter-spaced text is a row of per-character labels that auto-sizes to its characters and can't wrap. maxWidth therefore doesn't narrow it, and the row stays at its full natural width. Use shrinkToFit for letter-spaced text instead.

Outline

Use outline to draw a UIStroke around the glyphs, for text read over the 3D world or a busy background.

<Text text="Outlined" TextColor3={new Color3(1, 1, 1)} outline />
<Text
    text="Custom outline"
    TextColor3={new Color3(1, 1, 1)}
    outline={{
        color: Color3.fromHex("#1D2433"),
        thickness: 2,
        transparency: 0.2,
    }}
/>

The stroke uses ApplyStrokeMode.Contextual, so it outlines the text rather than the label's box.

  • outline={true} uses the typography style's outline, or the defaults: black, thickness 1, transparency 0.
  • An object overrides the style's outline (or the defaults) field by field, so { thickness: 2 } keeps the other fields.
  • outline={false} draws no outline, even if the typography style defines one.
  • When outline is unset, the style's outline is used if it has one; otherwise no outline is drawn.

outline is separate from the native TextStrokeColor3 and TextStrokeTransparency, which are still passed through unchanged. Letter-spaced text gets one stroke per character.

Shrink to fit

Set shrinkToFit to scale the whole text down, with a UIScale, so that it fits the available width. It's meant for single-line content such as titles and badges, especially letter-spaced text, which can't wrap.

<frame Size={new UDim2(0, 220, 0, 60)} BackgroundTransparency={1}>
    <Text
        text="LEADERBOARD"
        variant="display"
        letterSpacing={6}
        shrinkToFit
        shrinkMinScale={0.5}
    />
</frame>
  • The available width is maxWidth when set. Otherwise it is the parent's width minus the parent's UIPadding left and right.
  • While shrinkToFit is on, maxWidth is the width to shrink into and isn't applied as a size constraint. The other min and max props still apply.
  • The scale never goes above 1, so short text is never enlarged. shrinkMinScale (clamped to 0–1, default 0) sets the smallest scale; once it is reached, the text overflows.
  • The scale follows changes to the text, the parent's size, and reparenting.
  • The parent's width must not depend on the text. Inside a parent that auto-sizes on X, with no maxWidth, the text never shrinks.

Text size limits

Use minTextSize and maxTextSize to add a UITextSizeConstraint. They mainly matter for TextScaled text, which would otherwise grow to fill its box.

<Text
    text="Scaled"
    Size={new UDim2(1, 0, 0, 120)}
    AutomaticSize={Enum.AutomaticSize.None}
    TextScaled
    maxTextSize={32}
/>

Both are clamped to Roblox's 1–100 range. An unset minimum is 1 and an unset maximum is 100; a maximum below the minimum is raised to it. No constraint is rendered when both are unset.

Native properties

Text extends React.InstanceProps<TextLabel>, so native Roblox TextLabel properties can be passed directly to it.

<Text
    text="Custom label"
    Position={UDim2.fromScale(0.5, 0.5)}
    ZIndex={2}
    TextTransparency={0.25}
    Event={{
        MouseEnter: () => {
            print("Hovering text");
        },
    }}
/>

Some properties are managed internally by the component, including:

  • FontFace and FontSize, fully derived from variant/typography and weight. They cannot be set independently, even though React.InstanceProps<TextLabel> includes them.
  • Text, set from text.
  • TextXAlignment, set from align.
  • Size and AutomaticSize, used to auto-size the label to its content.

Props

Text-specific props

PropTypeDefaultDescription
textstringRequiredThe text content to display.
variantTextVariant"body"Selects a typography style from theme.typography.
typographyTypographyStyleThe resolved variant styleOverrides the typography style entirely, bypassing variant.
weightEnum.FontWeight | "bold"The variant's weight, or Enum.FontWeight.RegularOverrides the font weight. "bold" is shorthand for Enum.FontWeight.Bold.
align"Left" | "Right" | "Center""Left"Sets the horizontal text alignment.
TextWrapbooleantrueControls whether the text wraps across multiple lines.
TextColor3Color3theme.colors.intents.primary.default.textColorOverrides the text color.
LineHeightnumberThe resolved typography style's lineHeightOverrides the line height.
RichTextbooleantrueEnables or disables Roblox rich text tags in text.
TextScaledbooleanfalseScales the text to fit its container.
BackgroundTransparencynumber1Overrides the label's background transparency.
letterSpacingnumberThe resolved typography style's letterSpacingAdds spacing, in pixels, between characters. See Behaviour for how it's implemented.
outlineTypographyOutline | booleanThe resolved typography style's outline, if anyDraws a contextual UIStroke around the text. true uses the style's outline or the defaults, an object overrides it field by field, false disables it. See Outline.
shrinkToFitbooleanfalseScales the text down with a UIScale to fit maxWidth or the parent's content width. See Shrink to fit.
shrinkMinScalenumber0The smallest scale shrinkToFit may use, clamped to 0–1.
minTextSizenumber1 (when maxTextSize is set)Minimum text size for a UITextSizeConstraint, clamped to 1–100.
maxTextSizenumber100 (when minTextSize is set)Maximum text size for a UITextSizeConstraint, clamped to minTextSize–100.

TypographyOutline is { color?: Color3; thickness?: number; transparency?: number }. Unset fields default to black, 1, and 0.

Shared props

The text label also supports props inherited from the following interfaces.

InterfacePurpose
React.InstanceProps<TextLabel>Accepts native TextLabel properties, including Position, ZIndex, Change, and Event.
SizeElementProps (minWidth, maxWidth, minHeight, maxHeight only)Clamps the label's size with a UISizeConstraint. See Min and max size.

All other compatible native TextLabel properties, such as AnchorPoint, Visible, Rotation, TextStrokeColor3, TextTransparency, and TextTruncate, are also accepted—see Native properties above.

Behaviour

  • The label automatically sizes itself to fit its content (AutomaticSize.XY).
  • Setting either TextWrap={false} or the native TextWrapped={false} disables wrapping; both must be non-false for wrapping to stay enabled.
  • FontFace and FontSize are always derived from variant/typography and weight, and cannot be overridden directly, even though they are technically part of React.InstanceProps<TextLabel>.
  • Without variant or typography, the theme's body typography style is used.
  • The background is fully transparent by default (BackgroundTransparency={1}).
  • When a nonzero letterSpacing is set (directly or via the typography style), Roblox has no native letter-spacing property, so the text is instead split into one TextLabel per character laid out in a UIListLayout row. In this mode, RichText is forced off (markup can't survive being split apart), wrapping/truncation don't apply since each character auto-sizes to itself, and native properties other than TextColor3, TextStrokeColor3, TextStrokeTransparency, and TextTransparency — including Change and Event — are not forwarded to the underlying instances.
  • With none of minWidth, maxWidth, minHeight, maxHeight, outline, shrinkToFit, minTextSize, or maxTextSize set, and no outline in the typography style, no extra UI objects are added to the label.
  • The UISizeConstraint and the shrink UIScale go on the label, or on the letter-spaced row. The outline UIStroke and the UITextSizeConstraint go on the label, or on every character label when letter-spaced.
  • UIScale also shrinks the layout footprint, so siblings in a list layout close up around shrunk text.
  • With shrinkToFit, the scale stays where it is until the available width is known (no GUI parent, or a width of 0).

Theme values

Text reads from the active theme for:

  • theme.typography.<variant> — the font, size, weight, lineHeight, letterSpacing, and outline for each of display, title, heading, body, label, and caption. A style's outline is drawn unless the outline prop is false. No built-in theme sets outline.
  • theme.colors.intents.primary.default.textColor — the default text color when TextColor3 is not provided.

These values can be changed by providing a custom Clean UI theme.

GitHub Repository

On this page