Skip to main content

Text

A comprehensive typographic component with 28 type variants, 11 color roles, inline formatting, modifiers, and responsive text utilities.

Quick start
import { Text } from "mates-ui";

Text("Welcome back", { type: "headline-md" })
Text("Subtitle",     { type: "body-lg", color: "muted" })
Text("FEATURED",     { type: "overline" })
Text("$1,234",       { type: "stat", color: "primary" })

Type Scale — At a Glance

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-2)">
${Text("Display Large", { type: "display-lg" })}
${Text("Display Medium", { type: "display-md" })}
${Text("Display Small", { type: "display-sm" })}
${Text("Headline Large", { type: "headline-lg" })}
${Text("Headline Medium", { type: "headline-md" })}
${Text("Headline Small", { type: "headline-sm" })}
${Text("Title Large", { type: "title-lg" })}
${Text("Title Medium", { type: "title-md" })}
${Text("Title Small", { type: "title-sm" })}
${Text("Body Large", { type: "body-lg" })}
${Text("Body Medium", { type: "body-md" })}
${Text("Body Small", { type: "body-sm" })}
${Text("Label Large", { type: "label-lg" })}
${Text("Label Medium", { type: "label-md" })}
${Text("Label Small", { type: "label-sm" })}
${Text("OVERLINE", { type: "overline" })}
${Text("Caption", { type: "caption" })}
${Text("Lead paragraph", { type: "lead" })}
${Text("1,234", { type: "stat" })}
${Text("monospace", { type: "mono" })}
</x-col>
`;
renderApp(App, document.getElementById('app'));

Real-World Composition — Blog Article Header

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-2)" style="max-width:36rem;">
${Text("TECHNOLOGY", { type: "overline", color: "primary" })}
${Text("The Future of Web Components in 2025", { type: "display-md" })}
${Text("How modern frameworks are converging on a shared component model.", { type: "lead" })}
<x-row gap="var(--md-space-2)">
${Text("By Sarah Chen", { type: "body-md", bold: true })}
${Text("·", { type: "body-md", color: "muted" })}
${Text("March 15, 2025", { type: "caption" })}
${Text("·", { type: "body-md", color: "muted" })}
${Text("8 min read", { type: "caption" })}
</x-row>
</x-col>
`;
renderApp(App, document.getElementById('app'));

Real-World Composition — Content Card

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-2)" style="max-width:28rem;padding:var(--md-space-4);border:1px solid var(--md-color-border);border-radius:var(--md-radius-md);">
${Text("Getting Started with Reactive State", { type: "title-lg" })}
${Text("Learn how to manage reactive state with atoms, effects, and memos.", { type: "body-sm", color: "muted" })}
<x-row gap="var(--md-space-2)">
${Text("Dec 1, 2024", { type: "caption" })}
${Text("Tutorial", { type: "label-sm", color: "primary" })}
</x-row>
</x-col>
`;
renderApp(App, document.getElementById('app'));

Real-World Composition — Pricing Section

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-row gap="var(--md-space-4)" wrap>
<x-col gap="var(--md-space-3)" style="min-width:12rem;padding:var(--md-space-5);border:1px solid var(--md-color-border);border-radius:var(--md-radius-md);text-align:center;">
${Text("PRO", { type: "overline", color: "primary" })}
<x-row gap="var(--md-space-1)" align="center">
${Text("$49", { type: "stat", color: "primary" })}
${Text("/month", { type: "body-md", color: "muted" })}
</x-row>
${Text("✓ Unlimited projects", { type: "body-sm" })}
${Text("✓ Priority support", { type: "body-sm" })}
</x-col>
<x-col gap="var(--md-space-2)" style="min-width:12rem;padding:var(--md-space-5);border:1px solid var(--md-color-border);border-radius:var(--md-radius-md);text-align:center;">
${Text("ACTIVE USERS", { type: "overline", color: "muted" })}
${Text("12,847", { type: "stat", color: "success" })}
${Text("+23% from last month", { type: "caption", color: "success" })}
</x-col>
</x-row>
`;
renderApp(App, document.getElementById('app'));

Real-World Composition — Settings Section

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-5)" style="max-width:32rem;">
<x-col gap="var(--md-space-1)">
${Text("Notifications", { type: "headline-sm" })}
${Text("Configure how and when you receive notifications.", { type: "body-md", color: "muted" })}
</x-col>
<x-col gap="var(--md-space-4)" style="padding-left:var(--md-space-2);">
<x-col gap="var(--md-space-1)">
${Text("Email notifications", { type: "title-md" })}
${Text("Receive a daily digest of activity.", { type: "body-sm", color: "muted" })}
${Text("Requires a verified email address", { type: "label-md", color: "warning" })}
</x-col>
<x-col gap="var(--md-space-1)">
${Text("Push notifications", { type: "title-md" })}
${Text("Get instant alerts for mentions and replies.", { type: "body-sm", color: "muted" })}
${Text("Enabled", { type: "label-md", color: "success" })}
</x-col>
</x-col>
</x-col>
`;
renderApp(App, document.getElementById('app'));

Inline Formatting

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<p style="font-size:var(--md-text-sm);line-height:1.7;max-width:36rem;">
Press ${Text("Ctrl+S", { type: "kbd" })} to save.
You can ${Text("highlight important terms", { type: "mark" })} in docs.
This feature was ${Text("removed in v2", { type: "del" })} and
${Text("replaced in v3", { type: "ins" })} with a better API.
</p>
`;
renderApp(App, document.getElementById('app'));

Inline Types — Individual Showcase

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-3)">
<x-row gap="var(--md-space-1)">
${Text("Cmd", { type: "kbd" })} + ${Text("Shift", { type: "kbd" })} + ${Text("P", { type: "kbd" })}
</x-row>
${Text("highlighted text", { type: "mark" })}
${Text("Click to navigate", { type: "link" })}
${Text("deprecated API method", { type: "del" })}
${Text("newly added feature", { type: "ins" })}
${Text("/usr/local/bin/node", { type: "mono" })}
</x-col>
`;
renderApp(App, document.getElementById('app'));

Blockquote

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-2)" style="max-width:36rem;">
${Text("Design is not just what it looks like and feels like. Design is how it works.", { type: "blockquote" })}
<div style="padding-left:var(--md-space-4);">
${Text("— Steve Jobs", { type: "caption" })}
</div>
</x-col>
`;
renderApp(App, document.getElementById('app'));

Gradient & Decorative

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-3)">
${Text("Build Beautiful Interfaces", { type: "gradient" })}
${Text("Ship faster with a design system that scales.", { type: "lead" })}
</x-col>
`;
renderApp(App, document.getElementById('app'));

Text Modifiers

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-2)">
${Text("Italic text", { type: "body-md", italic: true })}
${Text("Bold text", { type: "body-md", bold: true })}
${Text("Underlined text", { type: "body-md", underline: true })}
${Text("Struck-through", { type: "body-md", strikethrough: true })}
${Text("Uppercased text", { type: "body-md", uppercase: true })}
${Text("Bold + italic + underline", { type: "body-md", bold: true, italic: true, underline: true })}
</x-col>
`;
renderApp(App, document.getElementById('app'));

Color Roles

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const ROLES = [
{ label: "default", color: undefined, text: "Primary body text — default color." },
{ label: "muted", color: "muted", text: "Secondary — descriptions, helper text." },
{ label: "primary", color: "primary", text: "Brand accent — links, active states." },
{ label: "info", color: "info", text: "Informational — tips, guidance." },
{ label: "success", color: "success", text: "Positive — confirmations, valid input." },
{ label: "warning", color: "warning", text: "Caution — potential issues, limits." },
{ label: "error", color: "error", text: "Negative — errors, failed operations." },
{ label: "disabled", color: "disabled", text: "Non-interactive — disabled controls." },
];

const App = () => () => html`
<x-col gap="var(--md-space-3)">
${ROLES.map(({ label, color, text }) => html`
<x-row gap="var(--md-space-3)">
${Text(label, { type: "label-sm", color: "muted", style: { minWidth: "5rem" } })}
${Text(text, { type: "body-md", ...(color ? { color } : {}) })}
</x-row>
`)}
</x-col>
`;
renderApp(App, document.getElementById('app'));

Alignment

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-4)" style="width:100%;">
<div style="padding:var(--md-space-3);border:1px dashed var(--md-color-border);border-radius:var(--md-radius-sm);">
${Text("Left-aligned text (default).", { type: "body-md", align: "left" })}
</div>
<div style="padding:var(--md-space-3);border:1px dashed var(--md-color-border);border-radius:var(--md-radius-sm);">
${Text("Center-aligned text — hero sections, empty states.", { type: "body-md", align: "center" })}
</div>
<div style="padding:var(--md-space-3);border:1px dashed var(--md-color-border);border-radius:var(--md-radius-sm);">
${Text("Right-aligned text — prices, timestamps.", { type: "body-md", align: "right" })}
</div>
</x-col>
`;
renderApp(App, document.getElementById('app'));

Truncation

import { html, renderApp } from 'mates';
import { Text } from 'mates-ui';

const LONG = "This is a very long piece of text that will be truncated to fit within its container boundary. It demonstrates how the truncation feature works in detail.";

const App = () => () => html`
<x-col gap="var(--md-space-5)" style="width:100%;">
<x-col gap="var(--md-space-2)">
${Text("Single-line truncate", { type: "title-md" })}
<div style="max-width:20rem;">
${Text(LONG, { type: "body-md", truncate: true })}
</div>
</x-col>
<x-col gap="var(--md-space-2)">
${Text("Multi-line clamp (maxLines: 2)", { type: "title-md" })}
<div style="max-width:28rem;">
${Text(LONG + " " + LONG, { type: "body-md", maxLines: 2 })}
</div>
</x-col>
<x-col gap="var(--md-space-2)">
${Text("Multi-line clamp (maxLines: 3)", { type: "title-md" })}
<div style="max-width:28rem;">
${Text(LONG + " " + LONG + " " + LONG, { type: "body-md", maxLines: 3 })}
</div>
</x-col>
</x-col>
`;
renderApp(App, document.getElementById('app'));

on, onClick

import { html, renderApp } from 'mates';
import { Text, Alert } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-4)">
<x-row gap="var(--md-space-3)">
${Text("Click me", {
type: "body-md",
color: "primary",
onClick: () => Alert("Text clicked!"),
})}
${Text("on mouse enter", {
type: "label-lg",
on: {
mouseenter() {
Alert("mouse entered");
},
},
})}
</x-row>
</x-col>
`;

renderApp(App, document.getElementById('app'));

Text

import { Text } from "mates-ui";
Prop Type Default Description
align "left" | "center" | "right" Text alignment.
as "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div" | "label" | "code" | "kbd" | "pre" Override the rendered HTML tag for correct document outline.
attr AttrMap HTML attributes on the root element.
bold boolean false Apply bold weight.
classes string | string[] Extra root classes — joined and appended after built-in classes.
classes string Extra CSS class name(s) appended to the root element (space-separated string).
color "default" | "muted" | "primary" | "inverse" | "error" | "success" | "warning" | "disabled" | "info" | "inherit" | "link" "default" Semantic color role applied to the text.
content* string | TemplateResult Text content to render.
data DataAttrMap Root `data-*` map (`testId` → `data-testid`). `testId` prop / `attr` win over `data`.
id string Root `id` shorthand (`attr.id` wins). Form native-control `id` props are unchanged.
italic boolean false Apply italic style.
maxLines number Multi-line truncation via -webkit-line-clamp. Overrides truncate.
nowrap boolean false Prevent text from wrapping.
on OnEventMap DOM event handlers on the root element.
onClick (e: MouseEvent) => void Click handler attached to the root element. Useful for interactive text like links.
selectable boolean Set to false to disable user text selection (user-select: none).
strikethrough boolean false Apply line-through decoration.
style StyleMap Inline CSS on the root element.
testId string Overrides the default data-testid="md-text".
truncate boolean false Clip to a single line with an ellipsis. Requires a width constraint.
type "display-lg" | "display-md" | "display-sm" | "headline-lg" | "headline-md" | "headline-sm" | "title-lg" | "title-md" | "title-sm" | "body-lg" | "body-md" | "body-sm" | "label-lg" | "label-md" | "label-sm" | "overline" | "caption" | "blockquote" | "kbd" | "link" | "mark" | "del" | "ins" | "gradient" | "mono" | "lead" | "stat" "body-md" Typographic scale variant or special inline/block type.
underline boolean false Apply underline decoration.
uppercase boolean false Transform text to uppercase with wider letter-spacing.

CSS tokens

Token Role
--md-color-error Error text color
--md-color-primary Primary accent text color
--md-color-success Success text color
--md-color-text Default text color
--md-color-text-disabled Disabled / non-interactive text color
--md-color-text-muted Muted / secondary text color
--md-color-warning Warning text color
--md-font-family Primary font stack
--md-font-mono Monospace font stack
--md-leading-tight … --md-leading-relaxed Line-height tokens
--md-text-xs … --md-text-4xl Font-size scale tokens
--md-weight-light … --md-weight-bold Font-weight tokens

Caveats

  • Use the `as` prop to override the inferred HTML tag for correct document outline (e.g. use display-md visually but render as h2).
  • `truncate` requires a width constraint on the element or an ancestor.
  • `maxLines` uses -webkit-line-clamp which works in all modern browsers but is technically a vendor prefix.
  • The `gradient` type uses background-clip: text — ensure you have a solid fallback color for older browsers.
  • `selectable: false` uses user-select: none and is useful for label text in interactive controls.