@teacss/preset-shortcuts
v0.5.0
Published
TeaCSS structural component shortcut preset.
Readme
@teacss/preset-shortcuts
An optional catalogue of structural component shortcuts. It lets applications reuse semantic class names without repeating long utility strings.
Usage
Select Standard and Shortcuts explicitly:
@preset "standard";
@preset "shortcuts";
@source "./src/**/*.{ts,tsx,html}";
@teacss;Shortcuts does not enable Standard. Unused classes emit no CSS.
Programmatic consumers import presetShortcuts from
@teacss/preset-shortcuts or teacss/preset-shortcuts. The direct package
also exports shortcuts and CustomShortcut:
import type { CustomShortcut } from "@teacss/preset-shortcuts";
export const applicationShortcuts: CustomShortcut[] = [
["surface", ["p:4", "rd:2x"]],
];Use the complete presetShortcuts() when installing the catalogue. If replacing
its shortcuts array programmatically, preserve the returned preset's other
fields: prose uses a private rule to keep descendant scope and ordering intact.
Naming
block card
block-part card-header
block--modifier card--sideUse - for an owned part and -- for a structural variation on the same
element. A modifier is always used with its base or part.
Use a singular component base for one component family. Reserve plural bases for compositions that group multiple instances of the singular component.
Component modifiers use complete, descriptive words such as
carousel--vertical, sheet--block-start, and
popover-content--block-start-inline-end. Standard's compact direction values
belong to atomic utilities; they are not abbreviations for component names.
Tooltip placements are tooltip-content--top, tooltip-content--bottom,
tooltip-content--inline-start, and tooltip-content--inline-end. These follow the
logical inline axis and mirror in RTL.
The preset owns structure: layout, sizing, geometry, type metrics, interaction mechanics, and color-independent motion. Applications own palette, tone, emphasis, and alternate sizes.
Ordinary utilities emit after shortcuts and override declarations with equal specificity. Repeat a shortcut's condition when overriding a conditional rule:
<input class="input opacity:100@disabled" disabled />Some modifiers use a compound selector to win over their base. For example,
card--side sets direction through .card.card--side; an unconditional
flex-direction:column cannot override it. Match the base condition instead:
<div class="card card--side flex-direction:column@[.card&]">...</div>Keep dropdown-content directly inside its dropdown root. Likewise,
collapse-title belongs directly inside collapse, and collapse-icon
directly inside that title. These ownership boundaries keep outer modifiers
and open states from affecting nested components.
The same direct ownership applies to chat media/bubbles, swap inputs/faces,
and card--side media. Keep the paths steps > step > step-row and
timeline > timeline-item; connectors, markers, and content belong directly
inside their step row, while timeline parts and connecting hr elements
belong directly inside their item. Nested components retain their own layout
and state.
filter reads selection and keyboard focus only from its direct options.
Place filter-reset directly inside that filter; wrapped inputs and nested
filters do not drive its collapsing or reset visibility. Checkboxes (or
data-mode="multiple") keep multi-select choices visible. Keep
menu-indicator directly inside its menu-action; only that action's
aria-checked="true" reveals the marker, not another ancestor's state.
Table pinning follows table > thead/tbody/tfoot > tr > cell ownership.
table-row draws borders on its direct cells; nested tables keep their own
pinning and row separators. Base table typography still flows into content.
toggle supports width and height utility overrides using an inline-size
query container and a fixed 0.125rem thumb gap. Keep a definite width and
height, zero track padding, and the container type when resizing it. Applications
still supply the thumb fill, for example bg-color:current@::before. In forced
colors, native inputs recover their native appearance; non-native switches keep
an outlined thumb. Applications remain responsible for labels and interaction.
Directional decorations and motion resolve RTL from the element's own
direction, including a self dir attribute and nested direction overrides.
focus-proxy gives a wrapper a native-style outline when a directly owned
input, textarea, or select matches :focus-visible. Use it when the native
control is visually hidden; dropzone, swap, and toggle include it. It does not hide
the input, provide a label, or forward focus from a nested component. A wrapping
toggle label keeps its native input directly inside the track so keyboard
focus outlines the visible control rather than the zero-sized input.
overlay-bounds shares viewport width/height limits and contained scrolling
across dropdown, popover, and tooltip surfaces. Positioning, collision
avoidance, focus management, and palette remain application-owned.
floating-label keeps its label visible at rest, when filled, and when
disabled. It moves without shrinking the label; the placeholder is hidden
until focus to avoid overlapping the label. Supply an associated label and
an opaque label background that matches the input surface.
rating keeps unselected choices at 80% opacity and focused choices at full
opacity. Native inputs restore native appearance in forced colors. Shape a
decorative pseudo-element instead of clipping the input itself, and hide that
decoration in forced colors. Supply an additional score cue (text or outlined
versus filled glyphs) and verify contrast with the application's palette.
transition-* helpers stop transitions under reduced motion. Prefer a
property-specific helper over transition-all. prose restores unordered and
ordered list markers and link underlines after Standard's preflight.
Site layout
The site family shares a page frame across headers, sections and footers.
site has a 100svh minimum height; a direct site-main child grows to keep
the footer at the bottom of short pages. Use semantic elements as appropriate.
Keep site-content directly inside site-section. Five tracks provide an
edge gutter, flexible side space, bounded content, flexible space, and an end
gutter. Each section owns its full-width bottom rule. Non-interactive pseudo-
elements draw the gutter and content edges without consuming content width.
Keep the content wrapper unpadded; pad its children to preserve aligned edges.
Consumers can set inherited CSS variables on a shared ancestor:
| Variable | Default |
| --- | --- |
| --site-content-width | 80rem |
| --site-gutter | clamp(1rem, calc(18.75vw - 6rem), 3rem) |
The gutter is capped at 25% of each section's width for narrow containers.
Nested scopes can override either variable. For example,
$site-content-width:[60rem] $site-gutter:1rem changes the frame locally.
site-intro centres its content with gap 5, a 48-unit minimum height (192px
at the default spacing), and padding 6 → 12 at md (24px → 48px). It grows
with content. site-rule is an empty, full-width separator band: minimum
height 3 (12px) and one bottom border. Use aria-hidden="true" for decoration
or an hr for a thematic break; height utilities can override either minimum.
site-grid > site-cell starts with one column; ordinary grid utilities choose
columns and breakpoints. The grid owns top/start borders; cells own bottom/end
borders. Keep it gapless with unspanned cells for continuous one-pixel seams.
A first grid directly in site-section > site-content omits its top border;
a last grid overlaps the section's bottom rule by one pixel. Standalone grids
keep their top border and have no negative margin. Use one grid per content
wrapper when it should meet section edges.
<section class="site-section border-color:$color-border border-color:$color-border@::before border-color:$color-border@::after">
<div class="site-content border-color:$color-border@::before border-color:$color-border@::after">
<div class="site-intro">Content grows beyond the minimum height.</div>
<div class="site-grid grid-columns:[repeat(2,minmax(0,1fr))]@md border-color:$color-border">
<div class="site-cell border-color:$color-border">First</div>
<div class="site-cell border-color:$color-border">Second</div>
</div>
</div>
</section>Colors, typography, word-breaking and column counts remain consumer-owned.
Color pseudo-element borders explicitly; borders do not inherit color.
Avoid clipping focus outlines. Existing hero, navbar, footer, and frame
remain independent compositions. No decorative hatch, node or ruler is included.
Code mockups
Use mockup-code > mockup-code-header + mockup-code-body to keep metadata
stationary while code scrolls. Titles wrap rather than truncate; the header
follows the surrounding direction and the code body remains LTR. Put each
pre > code directly inside the body. Rows share the longest line's width,
including highlights, and reserve a 3ch prefix column even without data-prefix.
The compact header has a 10-spacing-unit minimum height and grows with content.
Give a scrollable body tabindex="0", role="region", and an accessible name
using aria-labelledby or aria-label. Preserve its visible focus outline.
Applications supply colors, optional line highlights, and working actions.
Allow long action labels to wrap with consumer sizing and whitespace utilities.
Prefixes are presentation, not a substitute for meaningful code or status text.
Legacy mockup-code > pre markup still scrolls at the root; adopt the body
part for aligned gutters and a stationary header.
Long-form prose
prose covers headings h1–h6, paragraphs, links, quotations, rules, lists and
description lists, inline/block code, figures, media and tables. It supplies a
16px root type at the default theme scale, a 65ch logical reading measure and
inline centering. Ordinary utilities can change these defaults.
prose-hans and prose-hant are standalone script-specific compositions, not
owned parts or -- modifiers. Each includes the semantic baseline and adds a
matching SC/TC font stack, simplified/traditional glyph selection, Han spacing,
strict line breaking, justification, ruby placement and a 36em inline measure.
Like the base, they use overflow-wrap:anywhere so mixed Latin tokens do not
force narrow tables wider when text is enlarged.
Set lang on the content; font preferences do not convert text between scripts.
<article lang="zh-Hans" class="prose-hans">...</article>
<article lang="zh-Hant" class="prose-hant writing-mode:vertical-rl">...</article>Writing direction remains an ordinary utility. Code blocks stay horizontal
with margins that separate them in either flow; wrap the vertical article in
an application-owned scroll container. Digit combining requires explicit
inline wrappers with text-combine-upright:all.
Semantic descendant defaults have zero specificity. Conditions such as
prose@hover, prose@dark and prose@md apply to the scope, and pseudo-element
scopes emit no CSS. Targeted normal utilities override the defaults. Preserve
data-teacss-article-exclude on embedded UI: the whole subtree is excluded from
descendant rules, including nested prose scopes, but root typography inherits.
Prose owns no colors. Supply code backgrounds, border colors, link colors and
muted captions separately. No not-prose, size, color or invert variants exist.
Catalogue
Commons:
accessibility sr-only sr-visible focus-proxy
chevron chevron-up chevron-down chevron-left chevron-right
control control-icon control-disabled field-disabled checkable-base control-base field-base press-scale
layout hstack inline-hstack vstack centered inline-centered scroll-x scroll-y
overlay overlay-bounds
reset reset-heading reset-list reset-button reset-select reset-textarea reset-input reset-checkbox reset-radio
skeleton skeleton
transition transition-none transition-all transition-colors transition-opacity transition-shadow transition-transform
typography text-control text-label text-dense text-body text-description text-caption text-balance text-pretty text-eyebrow text-field plain-list heading-inherit truncateComponents:
alert alert alert-title alert-description
avatar avatar avatar-fallback avatars
badge badge badge--link
breadcrumb breadcrumb breadcrumb-list breadcrumb-item breadcrumb-link breadcrumb-current
btn btn
card card card-header card-body card-footer card-title card-description card-action card-media card-overlay card--side
carousel carousel-root carousel carousel--vertical carousel-item carousel-control carousel-control--start carousel-control--end carousel-control--top carousel-control--bottom
chat chat chat--start chat--end chat-media chat-header chat-footer chat-bubble
checkbox checkbox checkbox-control checkbox-indicator checkbox-indicator-mixed
collapse collapse collapse-title collapse-icon collapse-content collapse-folds
divider divider divider--block
dock dock dock-item dock-label
dropdown dropdown dropdown-panel dropdown-content dropdown--end dropdown--top
dropzone dropzone dropzone-input dropzone-content dropzone-selection
empty empty empty-header empty-media empty-title empty-description empty-content
fab fab
field field field-label field-hint input textarea field-group field-legend field-row field-error input-shell input-affix floating-label textarea--autosize
file-input file-input
filter filter filter-reset
footer footer footer--center footer-title
frame frame frame-side frame-main
hero hero hero-content hero-actions hero-decoration
indicator indicator indicator-item indicator-item--start indicator-item--center indicator-item--end indicator-item--top indicator-item--middle indicator-item--bottom
join join join--block join-separator join-text
kbd kbd kbd-group
list list list-row list-content list-media list-media--icon list-media--image list-title list-description list-col-wrap
listbox listbox listbox-option listbox-group listbox-empty
loading loading-shell loading
menu menu menu--horizontal menu-item menu-action menu-indicator menu-label menu-submenu menu-separator menu-shortcut
meter meter meter-header meter-value meter-track meter-indicator
mockup mockup-code mockup-code-header mockup-code-title mockup-code-language mockup-code-actions mockup-code-body mockup-phone mockup-phone-camera mockup-phone-display
modal modal modal-header modal-title modal-body modal-footer modal--motion modal--backdrop-motion
popover popover popover-content popover-header popover-title popover-description popover-content--block-start popover-content--block-start-inline-start popover-content--block-start-inline-end popover-content--inline-end popover-content--inline-end-block-start popover-content--inline-end-block-end popover-content--block-end popover-content--block-end-inline-start popover-content--block-end-inline-end popover-content--inline-start popover-content--inline-start-block-start popover-content--inline-start-block-end
navbar navbar navbar-brand navbar-start navbar-center navbar-end
otp otp otp-slot otp-separator
pagination pagination pagination-list pagination-item pagination-link pagination-ellipsis pagination-ellipsis-label
prose prose prose-hans prose-hant
progress progress progress-indicator progress-indicator--indeterminate
radio radio
range range range--vertical
rating rating
select select
sheet sheet sheet--block-start sheet--inline-end sheet--block-end sheet--inline-start
site site site-main site-section site-content site-intro site-grid site-cell site-rule
stat stats stats--vertical stats--horizontal stat stat-title stat-value stat-desc stat-figure stat-actions
status status
steps steps steps--vertical step step-row step-title step-content step-marker step-connector
swap swap swap-on swap-off swap-indeterminate swap--active swap--rotate swap--scale
table table-scroll table table-row table-body table-footer table-numeric table-caption table--pin-rows table--pin-cols
tabs tabs tab-list tab-list--vertical tab tab-content
timeline timeline timeline--vertical timeline-item timeline-start timeline-middle timeline-end timeline-box
toast toast toast-list toast-motion toast--top toast--middle toast--bottom
toggle toggle
tooltip tooltip tooltip-content tooltip-content--top tooltip-content--bottom tooltip-content--inline-start tooltip-content--inline-end tooltip-content--motionThe former rail, rail-side, rail-main, and --rail-offset names are now
frame, frame-side, frame-main, and --frame-offset, respectively; there
are no old-name aliases. Layout behavior is unchanged. The Storybook ID is
shortcuts-components--frame.
The TypeScript authoring sources live in src/commons and src/components.
Typography helpers are in typography.ts. Every class has a Storybook specimen
under shortcuts/commons/* or shortcuts/components/*.
Pre-1.0. The generated TypeScript preset is the supported runtime contract.
