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
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.
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'soutline, or the defaults: black, thickness1, transparency0.- 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
outlineis unset, the style'soutlineis 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
maxWidthwhen set. Otherwise it is the parent's width minus the parent'sUIPaddingleft and right. - While
shrinkToFitis on,maxWidthis 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 to0–1, default0) 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:
FontFaceandFontSize, fully derived fromvariant/typographyandweight. They cannot be set independently, even thoughReact.InstanceProps<TextLabel>includes them.Text, set fromtext.TextXAlignment, set fromalign.SizeandAutomaticSize, used to auto-size the label to its content.
Props
Text-specific props
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | Required | The text content to display. |
variant | TextVariant | "body" | Selects a typography style from theme.typography. |
typography | TypographyStyle | The resolved variant style | Overrides the typography style entirely, bypassing variant. |
weight | Enum.FontWeight | "bold" | The variant's weight, or Enum.FontWeight.Regular | Overrides the font weight. "bold" is shorthand for Enum.FontWeight.Bold. |
align | "Left" | "Right" | "Center" | "Left" | Sets the horizontal text alignment. |
TextWrap | boolean | true | Controls whether the text wraps across multiple lines. |
TextColor3 | Color3 | theme.colors.intents.primary.default.textColor | Overrides the text color. |
LineHeight | number | The resolved typography style's lineHeight | Overrides the line height. |
RichText | boolean | true | Enables or disables Roblox rich text tags in text. |
TextScaled | boolean | false | Scales the text to fit its container. |
BackgroundTransparency | number | 1 | Overrides the label's background transparency. |
letterSpacing | number | The resolved typography style's letterSpacing | Adds spacing, in pixels, between characters. See Behaviour for how it's implemented. |
outline | TypographyOutline | boolean | The resolved typography style's outline, if any | Draws 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. |
shrinkToFit | boolean | false | Scales the text down with a UIScale to fit maxWidth or the parent's content width. See Shrink to fit. |
shrinkMinScale | number | 0 | The smallest scale shrinkToFit may use, clamped to 0–1. |
minTextSize | number | 1 (when maxTextSize is set) | Minimum text size for a UITextSizeConstraint, clamped to 1–100. |
maxTextSize | number | 100 (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.
| Interface | Purpose |
|---|---|
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 nativeTextWrapped={false}disables wrapping; both must be non-falsefor wrapping to stay enabled. FontFaceandFontSizeare always derived fromvariant/typographyandweight, and cannot be overridden directly, even though they are technically part ofReact.InstanceProps<TextLabel>.- Without
variantortypography, the theme'sbodytypography style is used. - The background is fully transparent by default (
BackgroundTransparency={1}). - When a nonzero
letterSpacingis set (directly or via the typography style), Roblox has no native letter-spacing property, so the text is instead split into oneTextLabelper character laid out in aUIListLayoutrow. In this mode,RichTextis 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 thanTextColor3,TextStrokeColor3,TextStrokeTransparency, andTextTransparency— includingChangeandEvent— are not forwarded to the underlying instances. - With none of
minWidth,maxWidth,minHeight,maxHeight,outline,shrinkToFit,minTextSize, ormaxTextSizeset, and nooutlinein the typography style, no extra UI objects are added to the label. - The
UISizeConstraintand the shrinkUIScalego on the label, or on the letter-spaced row. The outlineUIStrokeand theUITextSizeConstraintgo on the label, or on every character label when letter-spaced. UIScalealso 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 of0).
Theme values
Text reads from the active theme for:
theme.typography.<variant>— thefont,size,weight,lineHeight,letterSpacing, andoutlinefor each ofdisplay,title,heading,body,label, andcaption. A style'soutlineis drawn unless theoutlineprop isfalse. No built-in theme setsoutline.theme.colors.intents.primary.default.textColor— the default text color whenTextColor3is not provided.
These values can be changed by providing a custom Clean UI theme.