Vela guides

Text and fonts

Text sizing, weight, alignment, wrapping and truncation — plus the host restriction the compiler does not actually enforce.

Text utilities write to the text properties of Roblox’s text instances — TextSize, TextColor3, FontFace, TextXAlignment, TextYAlignment, TextWrapped, TextTruncate. Three host elements have those properties: textlabel, textbutton, and textbox.

src/client/Title.tsx
<textlabel
className="text-2xl font-semibold text-slate-100 text-center align-middle"
Text="Match found"
/>

The host restriction is editor-only

Vela knows which utilities belong on which host element, and reports unsupported-host-utility when you get it wrong. That check lives in the LSP surface — diagnostics, hover, completions, and document colors.

The compiler never consults it. The transform pipeline does not check host tags at all, so <frame className="text-red-500" /> compiles cleanly and emits TextColor3 onto a Frame with no build-time warning of any kind.

The restriction does not apply to components

className also works on your own components, and there the rule is not merely unenforced — it does not exist. Vela has no idea which host element <Title /> eventually renders, so it treats every utility as allowed: the editor completes and hovers the full set inside a component’s className, including text-*, image-* and placeholder-*, and unsupported-host-utility is never reported there.

No warning anywhere, in the editor or the build
<Title className="text-2xl font-semibold" Text="Match found" />

Whether that text-2xl reaches a TextSize depends entirely on your component forwarding the props it does not consume down to a textlabel, textbutton or textbox. See How it works.

How text-* is disambiguated

text- is the most overloaded prefix in the whole system. One rule, applied in order, decides what a given text-* class means:

  1. If the payload is a text-size key (xs through 9xl), it is TextSize.
  2. If the payload is left, center, right, or justify, it is TextXAlignment.
  3. If the payload is wrap or nowrap, it is TextWrap.
  4. Everything else falls through to TextColor.

That fourth step is a catch-all, and it has a visible consequence: there is no such thing as an unrecognised text-* class. text-foo is treated as a color, the compiler looks up foo in theme.colors, does not find it, and reports unknown-theme-key — not unsupported-utility-family.

So when you misspell a size and see a theme-key warning, that is why. Reading unknown-theme-key on a text-* class as “you probably meant a size or an alignment” saves a lot of confusion.

Size

text-{size} sets TextSize in pixels.

ClassTextSize
text-xs12
text-sm14
text-base16
text-lg18
text-xl20
text-2xl24
text-3xl30
text-4xl36
text-5xl48
text-6xl60
text-7xl72
text-8xl96
text-9xl128

The set is fixed and does not come from the theme, so there is no way to add or change a size key. Anything outside the list falls through to the color branch as described above.

Weight

font-{weight} sets FontFace to a complete Font value:

new Font("rbxasset://fonts/families/SourceSansPro.json", Enum.FontWeight.SemiBold)
ClassEnum.FontWeight
font-thinThin
font-extralightExtraLight
font-lightLight
font-normalRegular
font-mediumMedium
font-semiboldSemiBold
font-boldBold
font-extraboldExtraBold
font-blackHeavy

Two names do not match their class: font-normal produces Regular, and font-black produces Heavy. Those are the Roblox enum member names, so the class names follow Tailwind while the emitted values follow Roblox.

Alignment

Horizontal alignment comes from text-left, text-center, and text-right, which set TextXAlignment.

Vertical alignment uses a different prefix — align-top, align-middle, and align-bottom, setting TextYAlignment to Top, Center, and Bottom. Note that align-middle maps to Center, matching the enum rather than the class name. Anything else after align- reports unsupported-text-alignment.

text-justify parses but does not resolve — Roblox’s TextXAlignment has no justified mode — and reports unsupported-text-alignment. There is no workaround; pick one of the three real alignments.

Wrapping and truncation

text-wrap sets TextWrapped = true and text-nowrap sets it to false.

truncate sets TextTruncate = Enum.TextTruncate.AtEnd, cutting overflowing text with an ellipsis at the end. It is a bare class with no payload, and AtEnd is the only truncation mode Vela emits.

src/client/PlayerRow.tsx
<textlabel className="text-sm text-nowrap truncate" Text={playerName} />

Placeholders

placeholder-* sets PlaceholderColor3 and is meaningful only on textbox — no other host element has the property. As with every host restriction on this page, the editor flags it and the compiler does not.

placeholder-transparent is an error (unsupported-color-key) because PlaceholderColor3 has no paired transparency property for the transparent keyword to set. See Colors and surfaces for how transparent works across the other families.

Typography families that do not exist

Several Tailwind typography families have no implementation in Vela. They are not partially supported and not silently degraded — they simply are not recognised, so they parse as an unknown family and report unsupported-utility-family:

  • leading-* — line height. Roblox exposes LineHeight on text instances, but no utility writes to it. Set the property directly.
  • tracking-* — letter spacing. There is no Roblox property for it at all.
  • uppercase, lowercase, capitalize — text transforms. Roblox has no text-transform property; change the string you pass to Text.

See also

  • Colors and surfaces — the color half of text-*, plus transparent and the shade rules.
  • Theming — where text-{color} keys come from.
  • Editor setup — getting the host-restriction warnings the compiler does not give you.
  • Diagnostics — every code and what triggers it.