styling-react-with-tailwind
9
总安装量
1
周安装量
#32387
全站排名
安装命令
npx skills add https://github.com/zenobi-us/zenobi-us --skill styling-react-with-tailwind
Agent 安装分布
amp
1
opencode
1
cursor
1
kimi-cli
1
kiro-cli
1
codex
1
Skill 文档
References:
- Guide – details on token system and patterns
Overview
This codebase uses:
- Tailwind CSS with semantic design tokens via
tw-colorsplugin - tailwind-variants (
tv()) for type-safe variant styling - Rose Pine color palette (light: Dawn, dark: Moon)
Token System
Color Token Pattern
{property}-{category}-{semantic}
Text tokens:
text-text-base– Primary body texttext-text-muted– Secondary/subtle texttext-text-link– Interactive link color (iris purple)text-text-strong– Emphasized text
Background tokens:
bg-background-base– Page backgroundbg-background-card– Card surfacesbg-background-button– Button backgroundsbg-background-informative– Info callouts
Border tokens:
border-border-muted– Subtle bordersborder-border-input– Form field bordersborder-border-informative– Info borders
Spacing & Layout
Standard Tailwind spacing scale. Use semantic sizing:
p-4,gap-2,m-0– standard spacingmax-w-7xl– content width constraints
Component Patterns
Pattern 1: Slots (Multi-element components)
Use when component has multiple styled children.
import { tv, VariantProps } from 'tailwind-variants';
import { classnames } from '~/core/classnames';
const Styles = tv({
slots: {
root: ['flex', 'items-center', 'gap-2'],
label: ['text-text-base', 'font-medium'],
icon: ['text-text-muted', 'w-4', 'h-4'],
},
variants: {
size: {
sm: { root: 'p-2', label: 'text-sm' },
md: { root: 'p-4', label: 'text-base' },
},
intent: {
primary: { root: 'bg-background-button', label: 'text-text-strong' },
ghost: { root: 'bg-transparent', label: 'text-text-muted' },
},
},
defaultVariants: {
size: 'md',
intent: 'primary',
},
});
type StyleProps = VariantProps<typeof Styles>;
type Props = StyleProps & {
className?: string;
children: React.ReactNode;
};
export function MyComponent(props: Props) {
const styles = Styles({ size: props.size, intent: props.intent });
return (
<div className={classnames(styles.root(), props.className)}>
<span className={styles.icon()}>*</span>
<span className={styles.label()}>{props.children}</span>
</div>
);
}
Pattern 2: Base (Single-element components)
Use when component is a single styled element.
import { tv, VariantProps } from 'tailwind-variants';
import { classnames } from '~/core/classnames';
const Styles = tv({
base: [
'border',
'border-border-muted',
'rounded',
'transition-colors',
],
variants: {
variant: {
solid: 'border-2',
dashed: 'border-dashed',
},
},
defaultVariants: {
variant: 'solid',
},
});
type Props = VariantProps<typeof Styles> & {
className?: string;
};
export function Divider(props: Props) {
const styles = Styles({ variant: props.variant });
return <hr className={classnames(styles, props.className)} />;
}
Pattern 3: Compound Variants
For conditional style combinations:
const Styles = tv({
base: ['rounded', 'px-4', 'py-2'],
variants: {
intent: { primary: '', danger: '' },
disabled: { true: 'opacity-50 cursor-not-allowed' },
},
compoundVariants: [
{
intent: 'primary',
disabled: false,
class: 'bg-background-button hover:bg-background-hover',
},
{
intent: 'danger',
disabled: false,
class: 'bg-red-500 hover:bg-red-600',
},
],
});
Key Utilities
classnames()
Always use for merging classes safely:
import { classnames } from '~/core/classnames';
// Merges and deduplicates Tailwind classes
classnames(styles.root(), props.className, isActive && 'ring-2');
Box with asChild
For polymorphic components:
import { Box } from '~/components/ds/box/Box';
<Box asChild className="text-text-link">
<a href="/path">Link styled as Box</a>
</Box>
Quick Reference
| Need | Use |
|---|---|
| Multiple styled elements | tv({ slots: { ... } }) |
| Single styled element | tv({ base: [...] }) |
| Variant types | VariantProps<typeof Styles> |
| Merge classes | classnames(a, b, c) |
| Conditional variants | compoundVariants: [...] |
| Purple accent | text-text-link, text-text-strong |
| Muted text | text-text-muted |
| Card background | bg-background-card |
Common Mistakes
- Using raw colors – Always use semantic tokens (
text-text-basenottext-gray-900) - Forgetting classnames() – Props className won’t merge properly without it
- Destructuring props – Use
props.xnot{ x }per codebase convention - Missing VariantProps – Always type variants for IDE completion