Data Display
Text
Text — the one component every string in the app goes through, instead of a <p>, a <span> or a <div> with a size class on it.
import { Text } from 'omaris' Examples
Basic
variant is how it looks, as is what it means. Set both when they differ; leave one out and it is inferred — a heading tag picks its own role, and a variant on its own renders a paragraph.
Deployments
Every push to main builds and ships. The last ten are kept so you can roll back.
<script lang="ts"> import { Text } from 'omaris';</script><div class="flex max-w-md flex-col gap-2"> <Text as="h2">Deployments</Text> <Text tone="muted"> Every push to <code>main</code> builds and ships. The last ten are kept so you can roll back. </Text> <Text variant="label-sm" tone="muted" class="mt-2">Updated 4 minutes ago</Text></div> Scale
Five roles, three sizes each. The variant carries size, line height, letter spacing and weight together — if you find yourself adding font-semibold after it, the role is wrong, not the weight.
The quick brown fox
The quick brown fox
The quick brown fox
The quick brown fox
<script lang="ts"> import { Text } from 'omaris';</script><div class="flex w-full flex-col gap-4"> <div class="flex flex-col gap-1"> <Text variant="label-sm" tone="muted" font="mono">display-sm</Text> <Text variant="display-sm">The quick brown fox</Text> </div> <div class="flex flex-col gap-1"> <Text variant="label-sm" tone="muted" font="mono">headline-md</Text> <Text variant="headline-md">The quick brown fox</Text> </div> <div class="flex flex-col gap-1"> <Text variant="label-sm" tone="muted" font="mono">title-lg</Text> <Text variant="title-lg">The quick brown fox</Text> </div> <div class="flex flex-col gap-1"> <Text variant="label-sm" tone="muted" font="mono">body-md</Text> <Text variant="body-md">The quick brown fox</Text> </div> <div class="flex flex-col gap-1"> <Text variant="label-sm" tone="muted" font="mono">label-md</Text> <Text variant="label-md">The quick brown fox</Text> </div></div> Tone and truncation
Colour is inherited by default, so Text stays legible on any surface. tone is for text that carries meaning of its own, and lines clamps to a fixed number with an ellipsis.
Inherits the surface
No tone needed here.
A component library is a set of decisions someone already made, so that the next person does not have to make them again badly.
lines={2}A component library is a set of decisions someone already made, so that the next person does not have to make them again badly.
<script lang="ts"> import { Text } from 'omaris'; const NOTE = 'A component library is a set of decisions someone already made, so that the next person does not have to make them again badly.';</script><div class="flex w-72 max-w-full flex-col gap-4"> <div class="rounded-xl bg-primary p-3"> <Text variant="title-sm" class="text-primary-foreground">Inherits the surface</Text> <Text variant="body-sm" class="text-primary-foreground/80">No tone needed here.</Text> </div> <Text tone="destructive" variant="label-md">Card declined</Text> <div class="flex flex-col gap-1"> <Text variant="label-sm" tone="muted" font="mono">{'lines={1}'}</Text> <Text lines={1}>{NOTE}</Text> <Text variant="label-sm" tone="muted" font="mono">{'lines={2}'}</Text> <Text lines={2}>{NOTE}</Text> </div></div> Numbers
tabular gives the digits a fixed width, so a column of figures lines up and a live counter stops twitching as it changes.
48,210.00
1,119.40
47,090.60
<script lang="ts"> import { Text } from 'omaris';</script><div class="flex w-64 max-w-full flex-col gap-2"> <div class="flex items-baseline justify-between gap-4"> <Text variant="label-md" tone="muted">Revenue</Text> <Text variant="title-sm" tabular>48,210.00</Text> </div> <div class="flex items-baseline justify-between gap-4"> <Text variant="label-md" tone="muted">Refunds</Text> <Text variant="title-sm" tabular>1,119.40</Text> </div> <div class="flex items-baseline justify-between gap-4"> <Text variant="label-md" tone="muted">Net</Text> <Text variant="title-sm" tabular>47,090.60</Text> </div></div> When to use it
Use it for
- Every string in the app: a heading, a paragraph, a cell, a caption.
variantis how it looks,asis what it means.<Text variant="title-md" as="h3">is a card title that is also a heading. - Five roles, three sizes each.
display-*for a stat card's hero number,headline-*for page and section titles,title-*for cards and dialogs,body-*for prose and cells,label-*for chips, headers and timestamps. - Text with its own meaning:
tone="muted"for secondary text,tone="destructive"for an error. Everything else inherits, so text on a coloured surface stays legible. - Figures.
tabularlines up a column and stops a live counter twitching;font="mono"for ids, hashes and anything compared character by character. - Clipping.
lines={1}for a filename in a row,lines={2}for a card description.
Not for
- A label inside a component that already sets its type, like a Button, Chip, Badge or Label → pass the string. The component owns the
label-*role. - A block of code → Code Block.
as="code"is for one identifier inside a sentence. - Long prose with its own headings, lists and links → the Typography guide covers that scale.
- A
sr-onlyspan, a single glyph or a layout-only wrapper → a raw utility class. An emoji →Emojifrom Emoji Picker.
Do
- Let
ascarry the semantics andvariantthe look. Set both when they differ; leave one out and it is inferred.as="h2"isheadline-md; a variant alone is a<p>(a<span>forlabel-*). - Pick the variant by the job of the text, not the size you want. Each variant sets size, line height, letter spacing and weight together. Needing
font-semiboldaftervariant="title-md"means the wrong variant. - Leave
wrapalone. Headings balance and body avoids orphans already. Setwrap="nowrap"withlines={1}only for a cell that must stay one line. - On a dashboard card:
display-smis the metric,title-mdthe card's name,body-smwithtone="muted"the comparison under it.
Don't
- Write
<p class="text-sm text-muted-foreground">. That is<Text variant="body-sm" tone="muted">, and it moves with the theme. - Use
weightto make a label bold.label-lgis already the weight buttons and tabs use. - Put
tone="default"on text inside a tinted card or a filled button. It goes illegible in dark mode. Let it inherit. - Use
display-lgtwice on a screen. It is the one number the screen is about.
Quick reference
variant display-lgdisplay-mddisplay-smheadline-lgheadline-mdheadline-smtitle-lgtitle-mdtitle-smbody-lgbody-md(default)body-smlabel-lglabel-mdlabel-sm
Role and size — the type token minus text-. Pick by the job the text does: display is the one hero number on a screen, headline titles a page or section, title titles a card or dialog, body is prose and cell contents, label is buttons, chips, tabs and column headers.
tone inherit(default)defaultmutedprimarysecondarytertiarydestructivesuccesswarninginfoinverse
Colour role. Inherits from the surface unless you say otherwise.
weight normalmediumsemiboldbold
Overrides the weight the variant already carries. Rarely needed.
align startcenterendjustify
Logical, so it follows the writing direction.
wrap normalbalanceprettynowrap
Overrides the wrapping the variant sets.
lines 123456
Clamps to N lines with an ellipsis.
font sansmono
Family. Inherits unless set; Arabic swaps itself out already.
API
Text
Text — the one component every string in the app goes through, instead of a <p>, a <span> or a <div> with a size class on it.
Two independent decisions: variant is how it looks, as is what it means. <Text variant="title-md" as="h3"> is a card title that is also a real heading. Leave one out and it is inferred — as="h2" picks a headline, and a variant on its own renders a <p> (or a <span> for label-*, which is inline).
The variant is the whole type decision. Each one carries size, line height, letter spacing and weight from the token of the same name, so adding font-semibold after variant="title-md" means the role was wrong, not the weight. Long-form wrapping is set for you too: headings balance, body avoids orphans.
Colour is inherited by default, so a Text inside a coloured surface stays legible without being told. Ask for tone when the text itself carries meaning — muted for secondary copy, destructive for an error.
import { Text } from 'omaris' <Text as="h1">Revenue</Text><Text variant="display-sm" tabular>$48,210</Text><Text tone="muted">Compared to last month.</Text><Text variant="label-sm" tone="muted" lines={1}>{file.name}</Text> Props
variant TextVariant How it looks — the type token minus text-. Pick by the job the text does: display is the one hero number on a screen, headline titles a page or section, title titles a card or dialog, body is prose and cell contents, label is buttons, chips, tabs and column headers. Each one carries size, line height, letter spacing and weight together. Defaults to body-md, or to the role that matches as when that is a heading.
display-lg- The one number on a screen. Rare in a dashboard.
display-md- A hero figure that shares the screen with something else.
display-sm- The metric at the top of a card — the usual display size here.
headline-lg- Page titles.
headline-md- Section titles.
headline-sm- Sub-sections, dialog headings.
title-lg- Card titles.
title-md- Dialog titles, list group headers.
title-sm- Dense card titles, table captions.
body-lg- Lead paragraphs and long-form prose.
body-md- The default — descriptions, cell contents.
body-sm- Secondary copy, captions, help text.
label-lg- Buttons and tabs.
label-md- Chips, column headers, form labels.
label-sm- Overlines, timestamps, the text inside a badge.
as TextElement What it means. Defaults to span for label-* and p for everything else. Use a heading tag for anything that is one — the look does not make it a heading, this does.
tone Defaults to 'inherit'
TextTone Colour role. Inherits from the surface by default, so a Text inside a coloured container stays legible; set it when the colour itself means something — muted for secondary copy, destructive for an error.
inherit- Takes the colour of whatever it sits in.
default- The page's primary text colour, stated.
muted- Secondary copy — captions, hints, timestamps.
primarysecondarytertiarydestructivesuccesswarninginfoinverse- For text on an inverted surface — a dark tooltip, an inverted toast.
weight TextWeight Overrides the weight the variant carries. If you want it, the role is probably wrong.
normalmediumsemiboldbold
align TextAlign Logical, so it follows the writing direction.
startcenterendjustify
wrap TextWrap Overrides the wrapping the variant sets — headings balance, body avoids orphans.
normal- Break wherever the line ends.
balance- Even line lengths — good for a heading of two or three lines.
pretty- No single-word last line. The default for `body-*`.
nowrap- One line, however long. Pair with `lines={1}` to clip it.
lines TextLines Clamps to N lines with an ellipsis. lines={1} is a single line.
123456
font TextFont Family. Inherits unless set; mono for ids, hashes and code.
sansmono- Ids, hashes, code, anything meant to be compared character by character.
tabular Defaults to false
boolean Fixed-width digits, for numbers that sit in a column.
for string Only with as="label": the id of the control it labels.
datetime string Only with as="time": the machine-readable date.
class string children Snippet