@small-batch/forge-tailwind-theme
v2.0.2
Published
Thin Atlassian semantic token bridge for Forge Custom UI apps
Maintainers
Readme
Forge Tailwind Theme
Thin Atlassian semantic token bridge for Forge Custom UI apps.
What v2 is
- shared semantic color bridge on top of Atlassian
--ds-*tokens - Tailwind v4
@theme inlinealiases for common semantic classes - optional entrypoints for base styles, spacing, radius, typography
- safe place for shared cross-app styling contract
What v2 is not
- not a full design system
- not Tailwind setup
- not plugin registration
- not app-specific tokens
- not charts, accent palette, sidebar system, or other broad default surfaces
Default entrypoint
@import "forge-tailwind-theme";
Default import exposes narrow semantic core only.
Included by default
- surfaces:
background,foreground,card,popover,sunken - actions:
primary,secondary,accent - semantic states:
success,warning,destructive,info,discovery - selection and links:
selected,disabled,link - form/chrome:
border,input,ring, semantic border colors - overlay:
blanket
Not included by default
- Tailwind import
- animation plugin import
- global base layer
- Atlassian spacing aliases like
p-100 - Atlassian radius aliases like
rounded-100 - typography aliases
- accent hue matrix
- chart palette
- optional sidebar aliases
Install
npm install github:Small-Batch/forge-tailwind-themeConsumer setup
App owns Tailwind setup.
/* src/styles/index.css */
@import "./tailwind.css";
@import "forge-tailwind-theme";
@import "./theme.css";Example Tailwind setup file:
@import "tailwindcss" source(none);
@source "../**/*.{js,ts,jsx,tsx}";
@import "tw-animate-css";Enable Forge theming before render:
import { view } from "@forge/bridge";
await view.theme.enable();Use Forge selector for dark-mode-aware custom tokens:
@custom-variant dark (&:is(html[data-color-mode="dark"] *));Do not rely on .dark or data-theme.
Optional entrypoints
Base styles
@import "forge-tailwind-theme/base.css";Adds:
* { @apply border-border outline-ring/50; }body { @apply bg-background text-foreground; }
Spacing aliases
@import "forge-tailwind-theme/spacing.css";Adds Atlassian spacing utilities like:
p-100gap-150m-300
Radius aliases
@import "forge-tailwind-theme/radius.css";Adds radius utilities like:
rounded-050rounded-100rounded-200rounded-round
Typography aliases
@import "forge-tailwind-theme/typography.css";Adds shared font family and weight aliases backed by Atlassian tokens.
Sidebar aliases
@import "forge-tailwind-theme/sidebar.css";Adds shadcn-compatible sidebar surface and accent aliases mapped to Atlassian semantic tokens.
App-local extension pattern
Keep domain tokens in app repo, after shared package import.
/* src/styles/theme.css */
@custom-variant dark (&:is(html[data-color-mode="dark"] *));
:root {
--risk-low-bg: var(--ds-background-accent-green-subtler);
--risk-low-fg: var(--ds-text-accent-green);
}
html[data-color-mode="dark"] {
--risk-low-bg: var(--ds-background-accent-green-subtle);
--risk-low-fg: var(--ds-text-accent-green);
}
@theme inline {
--color-risk-low-bg: var(--risk-low-bg);
--color-risk-low-fg: var(--risk-low-fg);
}Migration from v1
Breaking changes
v2 removes these from default import:
- Tailwind import
tailwindcss-animateplugin registration- base layer styles
- spacing aliases
- radius aliases
- typography aliases
- accent hue utilities
- chart tokens
- sidebar aliases (now optional)
Migration steps
- Move Tailwind imports/plugins into app repo.
- Keep single
@import "forge-tailwind-theme";in root stylesheet. - Move app-specific tokens into local
theme.css. - Add optional entrypoints only where needed:
base.cssspacing.cssradius.csstypography.csssidebar.css
- Keep
view.theme.enable()before render. - Use
html[data-color-mode="dark"]for custom dark overrides.
Example migration
Before:
@import "forge-tailwind-theme";After:
@import "./tailwind.css";
@import "forge-tailwind-theme";
@import "forge-tailwind-theme/base.css";
@import "./theme.css";Only import optional files app actually needs.
Utilities
import { cn } from "forge-tailwind-theme/utils";Recommended contract
- Atlassian owns primitive theme values
- package owns shared semantic aliases
- each app owns domain tokens, layout choices, and optional extras
