sutra-ui
v1.0.6
Published
A lightweight `sutra-*` utility classes into inline styles.
Readme
Sutra (सूत्र)
The Art of Utility. A Cultural-First CSS Library.
Sutra is a standalone utility system: you use sutra-* classes in your markup, and the runtime applies matching inline styles in the browser—no Tailwind CSS (or other CSS frameworks) required. Inspired by the Sanskrit term for a "thread" or "rule" that holds things together, Sutra gives you structured, culturally tuned tokens for color, type, spacing, and layout primitives.
Why Sutra?
- Atomic Precision: Utility-first
sutra-*tokens keep markup readable and your bundle free of a heavy CSS framework. - Cultural Aesthetics: Carefully chosen defaults for typography, spacing, and color palettes that draw inspiration from Indian art and heritage.
- Seamless Integration: Designed to work out-of-the-box with any modern React, Next.js, or Vue project.
"Just as a single thread (Sutra) creates a tapestry, our utility classes create your vision."
Features
- Scans the DOM for elements with
sutra-*utility classes. - Applies matching inline styles (the original classes stay intact).
- Auto-initializes on import, with an optional manual + scoped API.
- Built-in design tokens: palette (primary / secondary / tertiary / neutral + scales), semantic colors (
fg,muted,danger), and typography roles (sutra-font-headline,sutra-font-body,sutra-font-label).
Install
npm install sutra-uiUsage
Import the package once in your browser entry (or a Next.js client boundary). That registers the runtime that scans the DOM for sutra-* classes and applies inline styles. Then use sutra-* classes in HTML or in className like any other utilities.
Vite (vanilla JavaScript or TypeScript)
Create a project with the vanilla template, add the dependency, and import Sutra in your entry file before you render markup.
npm create vite@latest my-app -- --template vanilla-ts
cd my-app
npm install
npm install sutra-uiindex.html — include your module entry (Vite default):
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>src/main.ts:
import "sutra-ui";
document.querySelector<HTMLDivElement>("#app")!.innerHTML = `
<div class="sutra-p-24 sutra-bg-neutral sutra-text-fg sutra-font-body">
<p class="sutra-fs-18 sutra-font-semibold">Hello from Sutra</p>
</div>
`;Manual / scoped setup (optional — e.g. only a subtree):
import { initSutraUtilities } from "sutra-ui";
initSutraUtilities({ root: document.getElementById("app") ?? undefined });Advanced (tooling / tests): parseSutraClass, SUTRA_CLASS_PREFIX, and SutraStylePatch are exported from the package entry.
React (Vite, Create React App, etc.)
npm install sutra-uiSutra runs in the browser only (document). In main.tsx or index.tsx, import before createRoot so utilities are active before the first paint:
import "sutra-ui";
import { createRoot } from "react-dom/client";
import App from "./App";
createRoot(document.getElementById("root")!).render(<App />);Use sutra-* classes on className:
export function Hero() {
return (
<section className="sutra-bg-neutral sutra-text-fg sutra-p-24">
<h1 className="sutra-font-headline sutra-fs-display sutra-text-primary">Welcome</h1>
<p className="sutra-font-body sutra-text-muted">Body copy.</p>
</section>
);
}Next.js
Server Components and the server bundle have no document. Either import in a Client Component that wraps the tree (App Router), or import once in pages/_app (Pages Router). The package skips auto-init when document is missing (SSR), then initializes in the browser.
App Router
Put the side-effect import in a small client module and wrap your layout.
app/providers.tsx:
"use client";
import "sutra-ui";
export function Providers({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}app/layout.tsx:
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Pages Router
pages/_app.tsx:
import "sutra-ui";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}Alternative — manual init (e.g. scope to a subtree, or avoid the default document root):
"use client";
import { useEffect } from "react";
import { initSutraUtilities } from "sutra-ui";
export function SutraRoot({ children }: { children: React.ReactNode }) {
useEffect(() => {
initSutraUtilities({ root: document.body });
}, []);
return <>{children}</>;
}If you rely on manual initSutraUtilities only, do not also use the bare import "sutra-ui" entry (it auto-inits on document). Use named imports instead: import { initSutraUtilities, stopSutraUtilities } from "sutra-ui".
Minimal markup
<div class="sutra-p-2 sutra-bg-red sutra-text-center sutra-fs-16 sutra-font-semibold">
Hello
</div>Theme tokens in JS (charts, canvas, CSS-in-JS)
import { SUTRA_PALETTE, resolveThemeColor } from "sutra-ui";
// or: import { SUTRA_PALETTE } from "sutra-ui/theme";Design system (colors & typography)
Dark-first palette inspired by amber, gold, and warm neutrals:
| Family | Brand / DEFAULT |
|--------|-------------------|
| primary | #FFB300 |
| secondary | #C5A059 |
| tertiary | #7E6B4A |
| neutral | #0D0D0D |
Scales: use sutra-bg-primary-500, sutra-text-secondary-300, sutra-border-color-tertiary-600, etc. (50–900).
Semantic tokens (work with sutra-bg-*, sutra-text-*, sutra-border-color-*):
| Token | Typical use |
|-------|-------------|
| fg, muted, danger | Text hierarchy & states |
| surface, surface-elevated | Cards / panels on dark app background |
| border-subtle, ring | Inputs, dividers, focus affordance |
Typography:
| Class | Use |
|-------|-----|
| sutra-font-headline | Serif — hero titles (text-wrap: balance for nicer breaks) |
| sutra-font-body | Sans — paragraphs |
| sutra-font-label | Sans — small UI / captions |
| sutra-fs-display | Responsive clamp size for marketing headlines |
| sutra-antialiased | Sharper text on dark backgrounds (WebKit / macOS) |
<section class="sutra-bg-neutral sutra-text-fg sutra-antialiased sutra-p-24">
<h1 class="sutra-font-headline sutra-fs-display sutra-text-primary">Welcome</h1>
<article class="sutra-bg-surface sutra-border-w-1 sutra-border-color-border-subtle sutra-rounded-16 sutra-p-16">
<p class="sutra-font-body sutra-fs-16 sutra-text-muted">Body copy on dark.</p>
<span class="sutra-font-label sutra-text-secondary-400">Label</span>
</article>
</section>Best practices
- Layering: app shell
sutra-bg-neutral→ cardssutra-bg-surfaceorsutra-bg-surface-elevated. - Text: default copy
sutra-text-fg; secondarysutra-text-muted; accentssutra-text-primary-*. - Typography: add
sutra-antialiasedon dark sections; pairsutra-font-headlinewithsutra-fs-displayorsutra-fs-*for size. - Imports: tokens are available from the main entry or
import { SUTRA_PALETTE } from "sutra-ui/theme".
Project layout (contributors)
src/constants.ts—sutra-*prefix and helperssrc/theme/— palette, typography stacks,resolveThemeColor.ts,index.ts(barrel forsutra-ui/theme)src/parse*.ts— focused parsers (colors, typography, layout, animations, grid, …)src/parseSutraClass.ts— ordered pipeline: first matching parser winssrc/applySutraUtilities.ts— query DOM, apply patches, inject keyframes when neededsrc/domDocument.ts/src/elementStyle.ts— DOM helpers that work in browsers and Node + JSDOM (no reliance on missing globals likeDocument/HTMLElementin Node)src/index.ts— public API (initSutraUtilities,stopSutraUtilities, re-exports)
Supported Utilities
Spacing (padding / margin)
sutra-p-<n>/sutra-m-<n>->padding/margin- Directional variants:
sutra-px-<n>,sutra-py-<n>,sutra-pt-<n>,sutra-pr-<n>,sutra-pb-<n>,sutra-pl-<n>(and the same forsutra-m*)
Colors / alignment
sutra-bg-<color>->background-color: <color>sutra-text-<color>->color: <color>sutra-text-color-<color>-> same assutra-text-<color>(explicit CSS-style name)sutra-text-center|left|right|justify->text-align: ...
Typography
sutra-fs-<n>->font-size: <n>px(or pass a value through, e.g.rem/clamp)sutra-font-size-<n>-> alias ofsutra-fs-*(font-size)sutra-fs-display-> responsiveclamp(...)for large headingssutra-font-headline/sutra-font-body/sutra-font-label-> design-system rolessutra-antialiased-> WebKit / macOS font smoothing on dark UIssutra-font-light|normal|semibold|bold->font-weightsutra-font-weight-<n>-> numericfont-weight(e.g.400,700) or keyword (normal,bold, …)sutra-font-family-<value>->font-familysutra-line-height-<value>->line-height
Borders & radius
sutra-rounded-<n>->border-radiussutra-rounded-(t|r|b|l)-<n>-> corner radiisutra-border-w-<n>->border-width: <n>pxandborder-style: solidsutra-border-color-<color>->border-color
Layout / display
sutra-flex->display: flexsutra-grid->display: gridsutra-block->display: blocksutra-inline->display: inlinesutra-inline-block->display: inline-blocksutra-none->display: nonesutra-justify-<value>->justify-content- Includes aliases:
between,around,evenly,start,end
- Includes aliases:
sutra-items-<value>->align-items- Includes aliases:
start,end
- Includes aliases:
sutra-flex-wrap-<value>->flex-wrapsutra-flex-direction-<value>->flex-directionsutra-gap-<n>->gap: <n>px(or raw CSS unit/value)
Sizing
sutra-w-<n>->width: <n>pxsutra-h-<n>->height: <n>pxsutra-min-w-<n>->min-width: <n>pxsutra-max-w-<n>->max-width: <n>pxsutra-w-min(1080px,92vw)-> custom function/raw value support viasutra-w-*
Grid templates
sutra-grid-template-columns-240-1fr->grid-template-columns: 240px minmax(0,1fr)sutra-grid-template-columns-repeat-auto-fit-minmax-250-1fr->repeat(auto-fit, minmax(250px, 1fr))sutra-grid-template-columns-repeat-auto-fit-minmax-300-1fr->repeat(auto-fit, minmax(300px, 1fr))
Opacity
sutra-opacity-<0-100>->opacity(50→0.5)sutra-opacity-<decimal>-> unit opacity (0.35→0.35)
Overflow
sutra-overflow-x-<value>->overflow-x
Animation
Preset classes set animation and inject matching @keyframes (only for keyframes used on the page).
| Class | Effect |
| --- | --- |
| sutra-animate-spin | Full rotation (loading indicators) |
| sutra-animate-pulse | Opacity breathing |
| sutra-animate-bounce | Vertical hop |
| sutra-animate-ping | Scale + fade “radar” ring |
| sutra-animate-float | Slow vertical drift |
| sutra-animate-wiggle | Subtle rotation sway |
| sutra-animate-shake | Horizontal jitter |
| sutra-animate-fade-in | Fade + rise once (forwards) |
| sutra-animate-scale-in | Pop-in once (forwards) |
Notes
- Numeric tokens like
2are treated as2px. Tokens like10remor5%are passed through as-is. - The library runs in the browser only. If
documentis not available,initSutraUtilities()is a no-op. - Sutra watches class/DOM mutations after initialization and applies utilities automatically.
Docs-style Example
<main class="sutra-w-min(1080px,92vw) sutra-mx-auto sutra-py-24">
<section class="sutra-grid sutra-grid-template-columns-240-1fr sutra-gap-18">
<aside class="sutra-bg-#0f172a sutra-rounded-16 sutra-p-16">Sidebar</aside>
<article class="sutra-bg-#111827 sutra-rounded-16 sutra-p-20">
<h2 class="sutra-fs-28 sutra-m-0 sutra-font-bold">Utility-first docs layout</h2>
<p class="sutra-mt-8 sutra-line-height-1.5">No separate CSS file required.</p>
</article>
</section>
</main>