jixoai-ui
the terminal design language
loading the style sheet…
Skip to content
docs · print medium: screen

registry:ui · Data Display

prose — the reading region, eleven knobs and two channels

NOT <Typography> — that word is markdown's live user-facing vocabulary (<Markdown typography="relaxed"); the provider is <Prose>, rendering a div.jx-pure[data-jx-prose] host. Eleven frozen v1 knobs, every one an absentSlot in ProseDefaults: ABSENCE IS THE STATE — an unset knob emits nothing, stamps nothing, and the ambient channel (an outer prose region's declarations, or no opinion at all) keeps flowing; nested regions inherit every knob they do not set, nearest setter wins. Two channels carry the state: the JS scope (resolved through the plugin chain AT THE PROVIDER — a print-medium plugin can strip gradient/ground before CSS sees them — then provided through the typography lib's context pair) and the CSS residue sheet (prose.css), whose every rule sits at (0,2,0): above the face element rules, BELOW the markdown sheet. That ladder IS the sovereignty contract — an outer <Prose measure leading> can never fight <Markdown typography=…>; ink and flow pass through; chrome stays unaffected BY CASCADE; code/kbd stay mono under family; density stamps only for an explicit lane (W3-D2, the markdown trio founding law).

install — prose

$npx jixoai-ui add prose

https://ui.jixoai.com/r/prose.json

11 absentSlot knobs absence IS the state sovereignty by cascade gradient is fill-only

usage

Usage

Mount the region, compose paragraphs with the text family inside (the residue lanes hook [data-jx-text='p'] — the P component, not a bare p). Set only the knobs you hold opinions on; every unset knob lets the ambient flow.

Prose usage
<script lang="ts">
import Prose from '@ui/prose';
import { P } from '@ui/text';
</script>

<div class={cx(rt.prsGrid760)}>
  <div class={cx(rt.col8)}>
    <span class={cx(rt.note11)}>ambient — no knob set</span>
    <Prose>
      <P>The face's own channels carry this region: 14px body, the p lane at 1.6, ink at the foreground token. Nothing was stamped.</P>
    </Prose>
    <span class={cx(rt.note11)}>size + leading — scale and flow</span>
    <Prose measure="1.0625rem" leading={1.9}>
      <P>17px by inheritance; the P rides the region's 1.9 leading through the presence-gated residue rule. The same string would move a heading's em ladder for free — ambient size scales the ladder.</P>
    </Prose>
  </div>
  <div class={cx(rt.col8)}>
    <span class={cx(rt.note11)}>align justify + hyphens auto (lang on the host)</span>
    <Prose align="justify" hyphens="auto" lang="en" measure="13.5px">
      <P>Justified columns read best when the engine may break words: hyphens auto needs a lang on the host or an ancestor, and the two knobs are documented as a pair — justify without hyphens rivers, hyphens without justify never shows its work.</P>
    </Prose>
    <span class={cx(rt.note11)}>wrap pretty — the prose word</span>
    <Prose wrap="pretty">
      <P>Pretty wrapping breaks the final line where the reader needs it; balance is the heading-scope word, stable the tabular one.</P>
    </Prose>
  </div>
</div>

prose

The knob showcase — scale and flow. size rides pure inheritance (headings and paragraphs both scale, and a nested Markdown preset still beats it); leading is the P-only lane (headings keep their 1.25, pre keeps 1.55); align justify pairs with hyphens; wrap pretty is the prose word.

ambient — no knob set

The face's own channels carry this region: 14px body, the p lane at 1.6, ink at the foreground token. Nothing was stamped.

size + leading — scale and flow

17px by inheritance; the P rides the region's 1.9 leading through the presence-gated residue rule. The same string would move a heading's em ladder for free — ambient size scales the ladder.

align justify + hyphens auto (lang on the host)

Justified columns read best when the engine may break words: hyphens auto needs a lang on the host or an ancestor, and the two knobs are documented as a pair — justify without hyphens rivers, hyphens without justify never shows its work.

wrap pretty — the prose word

Pretty wrapping breaks the final line where the reader needs it; balance is the heading-scope word, stable the tabular one.

prose-usage.svelte svelte
<script lang="ts">
import Prose from '@ui/prose';
import { P } from '@ui/text';
</script>

<div class={cx(rt.prsGrid760)}>
  <div class={cx(rt.col8)}>
    <span class={cx(rt.note11)}>ambient — no knob set</span>
    <Prose>
      <P>The face's own channels carry this region: 14px body, the p lane at 1.6, ink at the foreground token. Nothing was stamped.</P>
    </Prose>
    <span class={cx(rt.note11)}>size + leading — scale and flow</span>
    <Prose measure="1.0625rem" leading={1.9}>
      <P>17px by inheritance; the P rides the region's 1.9 leading through the presence-gated residue rule. The same string would move a heading's em ladder for free — ambient size scales the ladder.</P>
    </Prose>
  </div>
  <div class={cx(rt.col8)}>
    <span class={cx(rt.note11)}>align justify + hyphens auto (lang on the host)</span>
    <Prose align="justify" hyphens="auto" lang="en" measure="13.5px">
      <P>Justified columns read best when the engine may break words: hyphens auto needs a lang on the host or an ancestor, and the two knobs are documented as a pair — justify without hyphens rivers, hyphens without justify never shows its work.</P>
    </Prose>
    <span class={cx(rt.note11)}>wrap pretty — the prose word</span>
    <Prose wrap="pretty">
      <P>Pretty wrapping breaks the final line where the reader needs it; balance is the heading-scope word, stable the tabular one.</P>
    </Prose>
  </div>
</div>

demo

Indent and the drop cap — the P-only lanes

indent is a first-line opinion the region holds about paragraphs only (headings never inherit one — a heading is not a paragraph); '2em' is the 中文稿纸 convention. initialLetter ships BOTH sheet arms — @supports initial-letter where the engine has it, the float ::first-letter fallback everywhere else — because a browser-class-dependent drop cap reads as a bug. The same P suppresses the indent: a drop cap plus a first-line indent double-counts. Drop caps KEEP printing on paper — the manuscript posture, the recorded decision.

indent + initialLetter
<!-- 中文稿纸惯例: the 2em first-line indent, P-only -->
<Prose indent="2em">
  <P>中文稿件每段首行缩进两字,标题永不缩进——标题不是段落。</P>
</Prose>

<!-- the drop cap: BOTH sheet arms, P-only, suppresses the indent -->
<Prose initialLetter={3}>
  <P>The first letter sinks three lines — @supports initial-letter where
  the engine has it, the float ::first-letter fallback everywhere else.</P>
</Prose>
indent 2em — 中文稿纸惯例

中文稿件每段首行缩进两字,正文齐头齐尾。段落之间不加空行,节奏全部由首行缩进承担——这是稿纸的惯例,区域的意见。

第二段同样缩进。缩进只作用于段落:区域内的标题永不继承首行缩进,因为标题不是段落。

initialLetter 3 — the drop cap

The drop cap sinks three lines in every engine: the modern initial-letter path inside @supports, the floated first letter everywhere else. If the same region also set indent, this P would suppress it — the compound rule.

demo

Ink, gradient, ground — and the chrome that ignores them

ink is the curated four-word union (default/muted/primary/destructive → the four foreground tokens) with a raw escape; links keep primary inside a region (the face B2 element rule — the recorded exception). The gradient is FILL-ONLY: background-clip: text with -webkit-text-fill-color, never color: transparent — currentcolor on a mark would resolve to the inherited transparent and vanish; marks restore solid by element rule, and --jx-ty-ink carries only color tokens so Heading's var-fallback utility never sees an invalid var. ground tints the region; Mark's own highlight law is untouched. And the orthogonality probe: chrome beside the paragraph is unaffected BY CASCADE — element-level declarations beat an inherited wrapper color.

the fill-only gradient
<Prose gradient={{ from: 'var(--primary)', to: 'var(--info)' }}>
  <Heading level={2}>A gradient the marks survive</Heading>
  <P>Fill-only: <Strong>strong</Strong> and <Mark>mark</Mark> keep their
  voice — currentcolor restores against the inherited solid ink.</P>
</Prose>
ink muted + ground muted — the quiet region

The region mutes its ink and tints its ground — and the chip beside this paragraph keeps its own ink: element-level declarations beat the inherited wrapper color, so control chrome never follows the region's ink by accident.

ink is the four-token union plus the raw escape — destructive here, any css color verbatim for everything else.

gradient on the heading + P hooks — marks restore solid

A gradient the marks survive

Fill-only lane: strong, mark and the rest keep their voice — the solid color stays inherited, so currentcolor restores against it. Print and forced-colors restores live in the sheet: the paged clone never re-runs the provider.

demo

Family — and the code that will not follow it

family words resolve to the theme's --font-* tokens; code and kbd keep their own mono element rules (face B1) — a family change is a prose opinion, never a code opinion, so InlineCode chips inside stay their calibrated mono regardless.

prose · family

family mono — the region, not the chips

The whole region sets in the theme's mono token — and the inline chip npm run verify keeps its own mono law anyway: code's face rules are element-level, so family is prose-only by construction.

prose-family-demo.svelte svelte
<script lang="ts">
import Prose from '@ui/prose';
import { P } from '@ui/text';
import InlineCode from '@ui/inline-code.svelte';
</script>

<div class={cx(rt.col8)}>
  <span class={cx(rt.note11)}>family mono — the region, not the chips</span>
  <Prose family="mono" measure="13px">
    <P>The whole region sets in the theme's mono token — and the inline chip <InlineCode lang="text">npm run verify</InlineCode> keeps its own mono law anyway: code's face rules are element-level, so family is prose-only by construction.</P>
  </Prose>
</div>
serif is a theme-token dependency — pending

The serif word resolves to var(--font-serif) — and this theme does NOT define --font-serif today (only --font-sans and --font-mono). Until the theme ships the token, family="serif" degrades to inheritance (the declaration computes to nothing). That is documented, not assumed: the knob is frozen with the word, the token is the theme's to add.

law

Sovereignty — the trio wins, by cascade

The layering ladder is the whole contract: face element rules (0,1,1) < prose residue rules (0,2,0) < the markdown sheet's §2a (0,2,1) and typography trio (0,3,0) < consumer utilities. An outer <Prose measure leading> wrapping a <Markdown typography=…> can never fight the preset — the trio's root declarations beat inheritance, and the residue rules lose to §2a inside [data-jx-markdown]. Zero JS masking, zero markdown changes; ink and flow knobs still pass through.

the sovereignty probe
<Prose measure="1.125rem" leading={2}>
  <Markdown typography="relaxed" {source} />
</Prose>

<!-- the trio's root declarations beat inheritance BY CASCADE: the outer
     size/leading can never fight <Markdown typography=…> inside -->
outer Prose measure 1.125rem + leading 2 — the relaxed preset ignores both, keeps its own 16/1.75

Sovereignty, demonstrated

The typography trio owns scale inside markdown — this relaxed preset stamps its own root declarations, and the outer <Prose measure leading> wrapper loses to them by cascade, not by JS masking.

Ink and flow knobs still pass through: the region mute tints these lines, but the scale stays the trio's.

and a plain P in the same region does follow the outer size — sovereignty is scoped to the markdown sheet, not the region

This paragraph is not inside markdown: it takes the region's 18px and the P lane's 2.0 leading. The ladder applies where the sheets speak — §2a only ever speaks inside [data-jx-markdown].

a11y

Accessibility

The host is a generic flow container — no role, no landmark claim; the reading semantics live in the content's own elements. The presence hooks are styling seams, never semantics. The two engine restores keep the words readable everywhere: forced-colors drops the clipped gradient for CanvasText ink, and print restores solid fill on paper.

Keyboard

KeyAction
—Not focusable — a reading region, not a control

ARIA

AttributeValueDescription
div[data-jx-prose]generic containerNo ARIA injected; the region is structural. Compose landmarks (section, article) around it as the document demands.
data-jx-ty-* attrspresence hooksdata-jx-ty-leading/-indent/-initial and data-jx-ty-ink="gradient" are styling/test seams stamped only when the knob is set — they carry no semantics.
gradient laneforced-colors restoreThe clipped fill drops to currentcolor under forced colors (CanvasText); nothing informational depends on the gradient.
drop cap::first-letter paintinitialLetter is paint on the real first letter — screen readers announce the word whole; it keeps printing on paper (the manuscript posture).

axes

Universal props

The eight-axis surface (explicit-props): size · shape · radius · density · color · theme · elevation · motion — each axis takes named steps, auto (inherit the ambient context; stamps nothing), an exact number (px · coefficient · dp · hue per axis), or query() for responsive/container-conditional values. THE §13 RENAME (Owner table ruling): the type-scale knob is measure now — never size; the freed name is the universal scale axis. Density stamps only for an EXPLICIT lane (the markdown trio's founding law — ambient control chrome keeps flowing).

Prose · universal props

The §13 rename: measure is the css type scale; size is the universal scale axis — both live on one host.

Named steps resolve via the alias ladder; the knobs stay sovereign by cascade.

prose-universal.svelte svelte
<Prose measure="1.0625rem" size={18}>…</Prose>

api

API

Eleven knobs, every one an absentSlot — no own, no fallback; absence IS the state. Consumer class merges LAST; consumer style lands after the emitted declarations (consumer wins on conflict); rest props pass through untouched.

Properties

PropertyTypeDefaultDescription
measure CssLengthabsentThe region's type scale — inheritance ONLY, never an element stamp: markdown sovereignty is a cascade fact, not a JS mask, and ambient measure scales the heading em ladder for free. RENAMED from size (explicit-props §13, W3-D2): a css measure is not the base-scale axis — the freed name belongs to the universal size lane.
leading numberabsentP-only line-height lane (headings keep their 1.25, pre keeps 1.55); applied through the presence-gated residue rule on [data-jx-text='p'].
family 'sans' | 'mono' | 'serif' | rawabsentWords resolve to the theme --font-* tokens — 'serif' NEEDS the theme to define --font-serif (this theme does not yet; it degrades to inheritance until it does) — or a raw font-family value. Code/kbd keep their own mono element rules.
ink 'default' | 'muted' | 'primary' | 'destructive' | rawabsentThe four foreground tokens or a raw color; also mirrors as --jx-ty-ink for Heading's var-fallback utility. Links keep primary inside a region (the face B2 element rule, the recorded exception).
gradient { from: string; to: string; angle?: number | string } | rawabsentFill-only lane: structured stops compose a linear-gradient (numeric angle to degrees, default 180deg) or a raw CSS image value verbatim. Never color: transparent — marks restore solid by element rule; print/forced-colors restores live in the sheet.
ground 'background' | 'card' | 'popover' | 'muted' | 'secondary' | 'accent' | 'transparent' | rawabsentThe region's ground token or raw value; Mark's own highlight law is untouched.
align 'start' | 'center' | 'end' | 'justify'absentInheritance lane; justify pairs with hyphens (docs guidance — justify without hyphens rivers).
indent CssLengthabsentP-only first-line indent; '2em' is the 中文稿纸 convention. Headings never inherit one; suppressed on a drop-cap P.
initialLetter 2 | 3 | 4 | 5absentDrop-cap depth; BOTH sheet arms (@supports initial-letter + the float ::first-letter fallback); suppresses indent on the same P; keeps printing on paper.
wrap 'pretty' | 'balance' | 'stable'absentpretty for prose scopes, balance for heading scopes, stable where lines must not reflow — guidance, not enforcement.
hyphens 'auto' | 'none' | 'manual'absentauto needs a lang on the host or an ancestor (documented); pairs with align justify.
children Snippet—The region's content — compose with the text family (P and the marks) so the residue lanes hook [data-jx-text='p'].
class string''cn()-merged onto the host LAST — consumer classes win through tailwind-merge dedupe.
...rest HTMLAttributes<HTMLDivElement>spreadEvery other attribute (including lang, needed by hyphens auto) passes through to the host div; consumer style lands after the emitted declarations.

Universal props

PropertyTypeDefaultDescription
size'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopethe base scale — root font-size; parts size in em
shape'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto''auto' · ambient scopecorner geometry (CSS corner-shape; §14 degrade table)
radius'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopecorner size; auto = the concentric broadcast (§3)
density'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopespacing/leading scale over the kernel channels (§4)
color'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string'auto' · ambient scopethe hue axis of the fixed oklch primary system (§5)
theme'light' | 'dark' | 'system' | 'auto''auto' · ambient scopelight/dark profile; system = the JS-mutable global (§6)
elevation'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number'auto' · ambient scopeofficial M3 levels over the surface ladder (§7)
motion'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number'auto' · ambient scopeintensity across the motion kernels (§8)
jixoai-ui ui.jixoai.com the jixoai design language

Theme

Brand hue

0°

Auto cycle · 24h