mit einem Klick
graffiti-best-practices
// Use when generating or refactoring Graffiti UI markup so output is class-first, semantic, accessible, responsive, and aligned with current Graffiti capabilities.
// Use when generating or refactoring Graffiti UI markup so output is class-first, semantic, accessible, responsive, and aligned with current Graffiti capabilities.
| name | graffiti-best-practices |
| description | Use when generating or refactoring Graffiti UI markup so output is class-first, semantic, accessible, responsive, and aligned with current Graffiti capabilities. |
| metadata | {"version":"1.9.0"} |
Generate high-quality Graffiti markup using current library constraints.
Graffiti is the baseline design layer when this skill is active: it provides the default system for elements, layout primitives, utilities, components, and color/theme tokens.
This skill extends Graffiti patterns; it does not create a parallel styling system.
This skill is strict about class-first composition, minimal inline style usage, semantic HTML, and repeatable quality checks.
It is also strict about template-first adaptation: when a matching hosted template baseline exists, start from that template and customize it.
Quality bar: passing the markup contract is necessary but not sufficient. Output must also clear an aesthetic bar (voice, density, imagery, restraint). Markup that satisfies every contract check but ships with AI-shaped content (generic copy, decorative gradients, invented SVG icons, fake numbers, emoji-as-icons) still fails. See references/AESTHETIC_GUIDE.md.
Audience: developers using Graffiti in real applications and websites.
SKILL.md - activation rules, boundaries, and execution workflowreferences/OUTPUT_CONTRACT.md - required response structure and scoring gatesreferences/GRAFFITI_SYSTEM.md - Graffiti identity, token/variable model, and source-of-truth lookup rulesreferences/COMPONENT_INTENT_MATRIX.md - role boundaries for core components (use-when, do-not-use, fallback)references/CANONICAL_SNIPPETS.md - critical pattern snippets that must be used as first-choice baselinesreferences/RECIPES_LAYOUTS.md - page shell and layout recipesreferences/RECIPES_SECTIONS.md - section-level recipes by intentreferences/RECIPES_COMPONENTS.md - component-level recipe snippetsreferences/ANTI_PATTERNS.md - failure mode catalog and detection heuristicsreferences/RECOVERY_TRANSFORMS.md - deterministic rewrite transformsreferences/EXAMPLES.md - prompt/response behavior examplesreferences/TROUBLESHOOTING.md - ambiguous prompt handling and recovery guidancereferences/AESTHETIC_GUIDE.md - taste / voice / density / imagery / anti-slop rules (output quality)references/THEMING_AND_TOKENS.md - color-scheme and opaque-scale gotchas, theme override chainreferences/MOBILE_AND_CONTAINERS.md - container queries vs media queries, drawer pattern, dvh + safe-areareferences/CHEAT_SHEET.md - fast "I want X, use Y" lookupActivate this skill when the request includes one or more of these signals:
--*) that are not part of Graffiti's documented token/component contracts.#hex, rgb(), oklch(...)) inline unless explicitly requested.references/AESTHETIC_GUIDE.md for the full anti-slop list.--blue, --red, etc.) and expect their opaque scales (--blue-opaque-N) to follow. Use a theme class instead. See references/THEMING_AND_TOKENS.md.@media queries for component-internal responsiveness. Default to @container queries with container-type: inline-size. See references/MOBILE_AND_CONTAINERS.md.Treat these as fixed truths for this skill:
https://graffiti-ui.com/base, https://graffiti-ui.com/utilities, https://graffiti-ui.com/elements, https://graffiti-ui.com/ui-blocks requested with Accept: text/markdown, plus topic routes like https://graffiti-ui.com/elements/buttonshttps://graffiti-ui.com/templates and template pages such as https://graffiti-ui.com/templates/landing, https://graffiti-ui.com/templates/dashboard, https://graffiti-ui.com/templates/blog, https://graffiti-ui.com/templates/settings, https://graffiti-ui.com/templates/ai-chat, https://graffiti-ui.com/templates/docs-portalreferences/* (guidance layer, never higher authority than source files)Before writing or editing markup, run this preflight in order:
https://graffiti-ui.com/base markdown and installed Graffiti CSS contracts.references/THEMING_AND_TOKENS.md to pick the right override level (theme class vs --primary swap vs component override token).@container per references/MOBILE_AND_CONTAINERS.md.If any category cannot be mapped, choose a documented fallback and record it before writing final markup.
For any surface that includes content (marketing, dashboard with copy, templates, blog, etc.) ALSO run this preflight per references/AESTHETIC_GUIDE.md:
<html> / app root) or locally (on a section/feature root). Default-canvas-with-no-theme is a deliberate choice, not a fallback. See references/THEMING_AND_TOKENS.md..box.invisible + gradient-* + monospace label as placeholder. Never invent decorative SVGs.package.json and existing imports first). If the project has no icon library, use the <span class="icon" aria-hidden="true"> placeholder pattern with a single Unicode glyph until a real icon is supplied. Never invent SVG icons more complex than a basic shape (circle / square / arrow / chevron / plus / minus / X / check). Never use emoji as feature icons. Never mix icon sets in one page.If theme / voice / density / imagery is ambiguous in the user's request and they didn't provide guidance, ASK before generating — do not silently choose generic SaaS defaults.
Classes are role-bearing primitives, not generic visual wrappers.
.box, .stack, .cluster, .split, .surface are fallbacks, not defaults. Reaching for them when a role-specific primitive exists is the single largest source of ugly, generic-looking Graffiti output.
Before composing any container with a neutral wrapper, walk the role menu in this order and stop at the first match:
.stat-card.feature-card.card (or .card.featured / .card.linked).callout + semantic variant.chat-thread + .chat-row + .bubble.log-card<details class="bordered"> + <summary><dialog> + .close.row / .form-actions / .form-option-row.input-group<form class="composer">.toc.icon-rail.workbench-panel inside .layout-rail.with-workbench.chip (with aria-pressed).tag (semantic variant first)<blockquote class="pull-quote">.eyebrowOnly after exhausting the role menu is .box / .stack / .cluster / .split / .surface allowed — and even then, justify why no role primitive fits.
Three-fit validation (apply once a role primitive is selected):
Hard boundaries:
.card and .card.featured are for repeating content units (article/product/plan-like records), not generic section/page wrappers..card.linked is for card-as-link preview units, not nav containers or generic anchor wrappers..stat-card is for KPI/metric values, not long-form copy or feature marketing blurbs..feature-card is for feature-list entries, not arbitrary content blocks..log-card is for activity entries (tool calls, deploys, audit lines), not generic cards..composer is for multi-line message composition with a toolbar; do not reach for it as a generic form wrapper..icon-rail and .workbench-panel belong inside .layout-rail shells; do not use them as standalone decoration..box / .stack / .surface and the result looks unstyled, you probably skipped the role menu above — go back and reselect.When using inline custom properties or token references:
https://graffiti-ui.com/base markdown and implemented in Graffiti CSS contracts..tag.success before --tag-color).--button-color, --tag-color, --bubble-*, --toggle-color, --callout-*).--* variable names in markup unless the user explicitly requests a project extension path.--gap, --layout-gap, --min-card-width, --max-width.class="theme-X") over inline-overriding hue tokens. Inline hue overrides do not propagate to opaque scales. See references/THEMING_AND_TOKENS.md.--bg or --fg, also pin color-scheme on the same element to prevent light-dark() resolution drift.Pick the lowest level that solves the requested change. Decide once, apply once.
| Scope of change | Apply theme at | Why |
|---|---|---|
| Whole application / site has a brand identity | class="theme-X" on <html> (or <body>) | One source of truth; every nested surface inherits |
| One section/feature needs a distinct visual mode | class="theme-X" on the section/feature root | Triggers per-hue opaque-scale re-derivation locally |
| Only the accent color needs to shift | style="--primary: ..." on the section root | Smallest correct override; safe inline |
| One component needs a documented variant tweak | Component override token (e.g. --bubble-bg, --callout-tint) | Respects theme contract |
| Status/role color (success / warning / error / info) | Semantic class variant (.tag.success, .callout.error, etc.) | Semantic variants always beat color overrides |
Available stock themes (verify against src/lib/themes/ before referencing):
theme-editorial, theme-paper, theme-system, theme-soft-consumer, theme-neon-arcade, theme-studio, theme-signal, theme-lumen. The unstyled canvas (no theme class) is also a valid choice — pick it deliberately, not by accident.
Hard rules:
--blue, --red, etc.) and expect the opaque scales (--blue-opaque-N) to follow. Use a theme class instead.!important to force a token to win — that always means the structural choice was wrong.Follow this sequence every time.
Classify intent
Resolve hosted template baseline first
https://graffiti-ui.com/templates/* for the closest intent match.Run system-first preflight
references/GRAFFITI_SYSTEM.md.Run aesthetic-first preflight (content surfaces)
references/AESTHETIC_GUIDE.md.Resolve source-of-truth class and variable contracts
https://graffiti-ui.com/base, https://graffiti-ui.com/utilities, https://graffiti-ui.com/elements, and https://graffiti-ui.com/ui-blocks with Accept: text/markdown and use documented classes/examples as canonical patterns.https://graffiti-ui.com/elements/buttons) when you only need one topic to reduce context noise.https://graffiti-ui.com/base markdown for global token names and categories.Create primitive mapping before coding
references/CHEAT_SHEET.md as a fast lookup when the intent is unambiguous.Run component intent fit check
references/COMPONENT_INTENT_MATRIX.md before writing markup.Resolve canonical snippets for critical patterns
references/CANONICAL_SNIPPETS.md baselines.Select canonical recipe path
references/OUTPUT_CONTRACT.mdreferences/RECIPES_LAYOUTS.md, references/RECIPES_SECTIONS.md, references/RECIPES_COMPONENTS.md, references/CANONICAL_SNIPPETS.mdBuild a class plan before writing markup
--* you intend to use and cite its source file.Plan responsive behavior
@media) or component-shaped (@container). Default to @container for component internals per references/MOBILE_AND_CONTAINERS.md.[popover].drawer + .drawer-toggle for mobile menus; do not write a JS-toggled menu.100dvh (not 100vh) for any "fill the visible viewport" need.Apply class-first decision tree
Write semantic structure first, then style with classes
header, nav, main, section, article, aside, footer, lists, tables, labels).Run accessibility minimum checks
aria-current/state attributes, table semantics, media alt text.Run responsiveness checks
Run class and variable validation checks
--* override must map to documented Graffiti token/override names.references/COMPONENT_INTENT_MATRIX.md.Run aesthetic compliance checks
references/AESTHETIC_GUIDE.md.Emit output using required contract
references/OUTPUT_CONTRACT.md section order.Handle ambiguity with deterministic defaults
references/TROUBLESHOOTING.md.Use this map before writing markup:
https://graffiti-ui.com/templates/landinghttps://graffiti-ui.com/templates/dashboardhttps://graffiti-ui.com/templates/bloghttps://graffiti-ui.com/templates/settingshttps://graffiti-ui.com/templates/ai-chathttps://graffiti-ui.com/templates/docs-portalIf no direct match exists, use recipes as primary source and state "No baseline template match found" in the output contract.
Is there an existing Graffiti class or class combination for this requirement?
Can this be represented as an approved token override?
--gap; use --tag-color only for custom categories when semantic tag variants do not fit).Is it a bounded layout exception (for example one-off max width wrapper)?
Status defaults:
.tag.success, .tag.warning, .tag.error, .tag.info.--tag-color as a fallback for non-status category colors..card.linked for card-as-link patterns instead of inline link reset styles..form-option-row for checkbox/radio label rows instead of inline display: inline-flex recipes..row inside forms/fieldsets for field wrappers (label + input + help text) instead of repeated stack + --gap compositions..form-actions for submit/cancel rows instead of bare cluster compositions (provides responsive stacking).<dialog> + .close for modal flows before custom modal wrappers or JS toggles.aria-current, open, checked state).table, thead, tbody, th, and td semantics.Treat output as failed if any hard fail occurs:
.card as generic wrapper)@media query used for component-internal responsiveness when @container was appropriateTreat output as pass only if all sections in references/OUTPUT_CONTRACT.md pass their checks AND the aesthetic checklist in references/AESTHETIC_GUIDE.md is clear.
references/OUTPUT_CONTRACT.mdreferences/GRAFFITI_SYSTEM.mdreferences/COMPONENT_INTENT_MATRIX.mdreferences/CANONICAL_SNIPPETS.mdreferences/RECIPES_LAYOUTS.mdreferences/RECIPES_SECTIONS.mdreferences/RECIPES_COMPONENTS.mdreferences/ANTI_PATTERNS.mdreferences/RECOVERY_TRANSFORMS.mdreferences/EXAMPLES.mdreferences/TROUBLESHOOTING.mdreferences/AESTHETIC_GUIDE.mdreferences/THEMING_AND_TOKENS.mdreferences/MOBILE_AND_CONTAINERS.mdreferences/CHEAT_SHEET.md