Skip to content
Back to skills

Craft Site

ASecurity

Craft CMS 5 front-end Twig development — atomic design, template architecture, components, Vite buildchain. Covers atoms/molecules/organisms, props/extends/block patterns, layout chains, view routing, content builders, image presets, Tailwind named-key collections, multi-brand CSS tokens, JavaScript boundaries (Alpine/DataStar/Vue, tabs, accordions), Vite asset loading, and front-end auth (login, registration, password reset, profiles).

  • 82 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 26, 2026
developmentjavascriptgojavaphpshellreactvuenextjsawsgit

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned October 7, 2026

npx -y skills add michtio/craftcms-claude-skills --skill craft-site --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Craft Site?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Craft Site
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/michtio-craft-site/badge)](https://www.skillsdirectory.com/skills/michtio-craft-site)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: craft-site
description: "Craft CMS 5 front-end Twig development — atomic design, template architecture, components, Vite buildchain. Covers atoms/molecules/organisms, props/extends/block patterns, layout chains, view routing, content builders, image presets, Tailwind named-key collections, multi-brand CSS tokens, JavaScript boundaries (Alpine/DataStar/Vue, tabs, accordions), Vite asset loading, and front-end auth (login, registration, password reset, profiles)."
when_to_use: "Triggers on: {% include ... only %}, {% embed %}, _atoms/_molecules/_organisms/_views/_builders, component--variant.twig, _component--props.twig, collect({}), utilities prop, data-brand theming, hero/card components, Matrix block rendering, craft.vite.script, vite.php, vite.config.ts, buildchain, per-page scripts, Blitz static/page caching, ImageOptimize, Imager-X, responsive images, srcset, image transforms, SEOmatic meta/OpenGraph/JSON-LD, Sprig, htmx, multi-language, hreflang, localization, Formie form styling, login/registration form, RSS/Atom/JSON feeds, XML sitemap, search page, .search(), headless GraphQL, Next.js/Nuxt/Astro integration, example-templates command, render builder, fluent BaseTag {{ tag.render() }}, progressive enhancement. Always use when creating, editing, or reviewing Craft front-end Twig templates, components, layouts, views, builders, buildchain, or front-end auth — including plugin template integration (Blitz, SEOmatic, Sprig, Formie, Imager-X). Do NOT trigger for PHP plugin/module development (craftcms) or content modeling (craft-content-modeling)."
---

# Craft CMS 5 — Front-End Twig (Atomic Design)

Atomic design system patterns for Craft CMS 5 site templates. Vanilla Twig —
no module dependency. Works with any Craft 5 project.

This skill is scoped to **front-end template architecture** — component design,
routing, composition, theming, and buildchain. For extending Craft (plugins,
modules, PHP), see the `craftcms` skill.

## Companion Skills — Always Load Together

When this skill triggers, also load:

- **`craft-twig-guidelines`** — Twig coding standards: variable naming, null handling, whitespace control, include isolation, Craft helpers. Required for any Twig code.
- **`craft-content-modeling`** — Sections, entry types, fields, Matrix, relations. Required when deciding what content to query or how templates access data.
- **`ddev`** — All commands run through DDEV. Required for running Vite, npm, and Craft CLI commands.
- **`craft-cloud`** — When the site is hosted on Craft Cloud (detect via `craft-cloud.yaml` at the repo root or `craftcms/cloud` in `composer.json`). Required for edge static caching rules, `cloud.esi(...)` dynamic islands inside cached pages, edge image transform constraints, and the `csrfInput()` requirement on cacheable pages.
- **`servd`** — When the site is hosted on Servd (detect via `servd.yaml` at the repo root or `servd/craft-asset-storage` in `composer.json`). Required for Servd static caching, `{% dynamicInclude %}` islands in cached pages, running Blitz in reverse-proxy mode, and off-server image transforms.

## Documentation

- Twig in Craft: https://craftcms.com/docs/5.x/development/twig.html
- Template tags: https://craftcms.com/docs/5.x/reference/twig/tags.html
- Template functions: https://craftcms.com/docs/5.x/reference/twig/functions.html
- Twig 3 docs: https://twig.symfony.com/doc/3.x/

Use `WebFetch` on specific doc pages when a reference file doesn't cover enough detail.

## Common Pitfalls (Cross-Cutting)

- Missing `only` on `{% include %}` — ambient variables leak in silently.
- Variant logic via conditionals (`{% if variant == 'x' %}`) instead of extends/block.
- Naming atoms by parent context (`hero-button`) instead of visual treatment (`button--primary`).
- `utilities` prop used as override — it's additive. Override via named-slot merge.
- Queries inside views — views receive data, they don't fetch it.
- Missing `.eagerly()` on relation fields in views — causes N+1 queries.
- Missing `devMode` fallback in builders for unknown block types.
- Hardcoded Tailwind colors (`bg-yellow-600`) instead of brand tokens (`bg-brand-accent`).
- Mixing buttons and links — buttons are actions (resolve to `<a>`, `<button>`, or `<span>` from props), links are navigation (always `<a>`). Separate atom categories.
- Tracking/analytics inside components — decouple to data attributes at view/page level.
- Forgetting `project-config/touch` after editing YAML outside the CP — Git pulls, manual edits, and merge conflict resolution don't update `dateModified`. Run `ddev craft project-config/touch` then `ddev craft up`, or `craft up` on other environments won't detect the change.

## Reference Files

Read the relevant reference file(s) for your task. Multiple files often apply together.

**Task examples:**
- "Build a new card component" → read `atomic-patterns.md` + `composition-patterns.md` + `component-inventory.md` + `tailwind-conventions.md`
- "Set up a new project's template structure" → read `boilerplate-routing.md` + `component-inventory.md`
- "Add a content builder for a Matrix field" → read `boilerplate-routing.md` + `composition-patterns.md`
- "Handle responsive images" → read `image-presets.md` + `plugins/image-optimize.md`
- "Add multi-brand theming" → read `tailwind-conventions.md`
- "Decide between Alpine and Vue for a feature" → read `javascript-boundaries.md`
- "Compose Tailwind classes without conflicts" → read `tailwind-conventions.md` + `twig-collections.md`
- "Understand atomic design methodology" → read `atomic-design.md`
- "Set up Vite + Tailwind in a new Craft project" → read `vite-buildchain.md`
- "Debug why assets aren't loading in production" → read `vite-buildchain.md`
- "Look up a `craft.vite.*` Twig function (asset, register, critical CSS)" → read `plugins/vite.md`
- "Install GTM/analytics/CMP in a Craft project" → read `third-party-integration.md`
- "Can't override a plugin's front-end CSS / plugin styles beat mine" → read `third-party-integration.md` (Plugin CSS Loads After Yours)
- "Replace a plugin's template with my own / plugin widget stopped enhancing" → read `third-party-integration.md` (Hand-Written Templates for Plugin Widgets)
- "Configure SEOMatic for a section" → read `plugins/seomatic.md`
- "Set up Blitz caching with Cloudflare" → read `plugins/blitz.md`
- "Add a form to a page" → read `plugins/formie.md`
- "Configure CKEditor with nested entries" → read `plugins/ckeditor.md`
- "Build a navigation menu" → read `plugins/navigation.md`
- "Add a link field to a component" → read `plugins/hyper.md`
- "Set up redirects for a site" → read `plugins/retour.md`
- "Add recurring/repeating dates to entries" → read `plugins/timeloop.md`
- "Create a JSON API endpoint" → read `plugins/element-api.md`
- "Debug N+1 queries in templates" → read `plugins/elements-panel.md`
- "Run a security audit" → read `plugins/sherlock.md`
- "Embed a YouTube/Vimeo video as an asset" → read `plugins/embedded-assets.md`
- "Configure email delivery via SES" → read `plugins/amazon-ses.md` + `third-party-integration.md`
- "Build a language switcher" → read `multi-site-patterns.md`
- "Add login/registration to the front end" → read `auth-flows.md`
- "Build a user profile edit page" → read `auth-account.md`
- "Set up password reset flow" → read `auth-flows.md`
- "Set up hreflang tags" → read `multi-site-patterns.md`
- "Plan a multi-language site architecture" → read `multi-site-patterns.md`
- "Add live search without JavaScript" → read `plugins/sprig.md`
- "Build reactive filtering or load-more" → read `plugins/sprig.md`
- "Import data from an external feed" → read `plugins/feed-me.md`
- "Set up responsive images with Imager-X" → read `plugins/imager-x.md`
- "Build a search page" → read `search.md`
- "Configure search settings" → read `search.md` (Search Configuration)
- "Rebuild the search index" → read `search.md` (Rebuilding)
- "Create an RSS feed" → read `feeds.md`
- "Build an XML sitemap" → read `feeds.md` (XML Sitemap)
- "Create a JSON Feed" → read `feeds.md` (JSON Feed)
- "Set up a headless Craft CMS with Next.js" → read `headless.md`
- "Fix GraphQL preview tokens" → read `headless.md`
- "Consume Craft GraphQL API from a front-end framework" → read `headless.md`
- "Use entry.render() for reusable card components" → read `element-partials.md`
- "Set up _partials/ templates for entries" → read `element-partials.md`
- "Render Matrix blocks with partials" → read `element-partials.md`
- "Ship example templates with a plugin (bundle + install command)" → read `example-templates.md`
- "Build a fluent front-end render/tag builder (craft.<handle>.thing().render())" → read `example-templates.md`


| Reference | Scope |
|-----------|-------|
| `references/atomic-design.md` | Methodology: Brad Frost's atomic design principles, 5-to-3 tier compression, composability, context-agnostic naming, classification problem, decompose-downward workflow. Technology-independent. |
| `references/atomic-patterns.md` | Individual component construction: props/extends/block pattern, variant file mechanics, button/link/text/icon atom implementations |
| `references/composition-patterns.md` | Component composition: molecule pattern, organism pattern, structural embed pattern, include/extends/embed decision table, calling conventions, creating new components |
| `references/component-inventory.md` | Classification methodology: decision tree, naming conventions, file naming, props design, scaffold guidelines, tier promotion, audit checklist |
| `references/boilerplate-routing.md` | Template chain: layout hierarchy, Craft section template paths, global variables, routers, views, content builders, directory structure |
| `references/tailwind-conventions.md` | Class composition: named-key collections, standard key names, `utilities` prop, variant-based dark mode, spacing preference. Assumes Tailwind CSS — adapt patterns to your CSS framework. |
| `references/vite-buildchain.md` | Craft CMS Vite setup: nystudio107 plugin bridge, `config/vite.php`, `vite.config.ts`, `craft.vite.script()`, conditional per-page loading, Tailwind v4 integration, DDEV configuration |
| `references/image-presets.md` | Image handling: single atom with presets, srcset/sizes, ImageOptimize vs Craft Cloud, hosting strategies |
| `references/javascript-boundaries.md` | JS decision tree: Twig → Alpine/DataStar → Vue, mount points, data handoff, coexistence rules |
| `references/twig-collections.md` | `collect()` method reference: creating, accessing, transforming, filtering, sorting, slicing, arrow functions |
| `references/third-party-integration.md` | Script loading order, CMP (UserCentrics/CookieBot), GTM/sGTM data layer, analytics (Fathom/Plausible), AWS SES transport, n8n webhooks, plugin CSS cascade (loads after yours) + hand-written templates for plugin widgets, Blitz compatibility, full head template example |
| `references/multi-site-patterns.md` | Language switchers, hreflang tags, site architectures (subfolder/domain/subdomain/multi-brand), cross-site queries, static translations, site-specific templates, multi-site forms, site detection |
| `references/auth-flows.md` | Front-end authentication forms: login, registration, password reset, set new password |
| `references/auth-account.md` | Account management: edit profile, email verification, navigation partial, access control tags, user session helpers, GeneralConfig auth settings |
| `references/search.md` | Search: syntax, Twig queries, configuration, indexing, rebuilding, score and ranking |
| `references/feeds.md` | Feeds: RSS 2.0, Atom, JSON Feed, XML sitemap, custom routes, date filters |
| `references/headless.md` | Headless & hybrid: headlessMode, GraphQL API, CORS, preview tokens, Next.js/Nuxt/Astro integration |
| `references/element-partials.md` | Element partials: entry.render(), _partials/ directory, template lookup, custom variables, eager loading in partials |
| `references/example-templates.md` | Plugin front-end delivery: Craft Commerce-style example-template bundles (canonical folder, `_private/layouts/` shell, per-page `{% extends %}`/`{% block main %}`, `index.twig` redirect, install console command with rename/`--overwrite`), fluent `craft.<handle>.<thing>({...}).render()` BaseTag builders, progressive-enhancement discipline |

### Plugin References

Per-plugin configuration, Twig API, and pitfalls live in the **`craft-plugins`** skill (`skills/craft-plugins/references/<plugin>.md`) — kept there so they're discoverable from back-end, migration, and deployment tasks too, not just front-end ones.

When a front-end task involves a specific plugin — Formie form styling, SEOmatic meta, Blitz caching, Imager-X / ImageOptimize transforms, Sprig components, CKEditor, Hyper links, Navigation, Embedded Assets, Vite, Typogrify, Colour Swatches — load the `craft-plugins` skill and open the matching reference.


## Component System Conventions

One canonical component system across all projects. Atoms are context-agnostic — always named by visual treatment, never by parent. HTML element type is resolved from props (`url` → `<a>`, `type` → `<button>`, fallback → `<span>`).

External link detection is derived from the URL, never passed as a prop. Components auto-apply `target="_blank"`, `rel="noopener noreferrer"`, external icon, and sr-only text when a URL is external.

FontAwesome is the universal icon system. Icons are passed as FA class strings.

Visual variants use extends/block — base template defines structure, variant overrides classes. Never use conditional logic to switch between variant styles. For structural skeletons with content slots, use `{% embed %}` — see `composition-patterns.md`.

Image handling uses a single atom with config-driven presets, not separate variant files per context.

## CSS & Theming Conventions

This skill assumes Tailwind CSS for class composition examples. Adapt patterns
to your CSS framework — the architectural principles (named keys, additive
utilities, semantic tokens) are framework-agnostic.

Class collections use named keys per style concern — this is the primary mechanism for preventing conflicts. The `utilities` prop is additive (extending), not overriding. Override specific concerns via named-slot merge.

Multi-brand theming uses CSS custom properties activated by `data-brand="{{ currentSite.handle }}"` on `<html>`. Components reference semantic Tailwind classes (`bg-brand-accent`) resolved via CSS variables. Template-level brand overrides only exist when the HTML structure itself differs between brands — not for color/font/spacing differences.

Token naming follows three layers: primitives (`--brand-{color}-{shade}`), semantics (`--brand-{purpose}`), and framework mapping (`--color-brand-{purpose}`).

Tailwind v4 cascade layers don't fix class conflicts within the same utilities layer. Named-key collections remain necessary.

## Routing Conventions

PHP handles data, Twig handles presentation. Views receive data through includes — they never query it themselves.

`collect()` is used for both props and class building. The full Collection API is available in Twig via Craft.

The JS boundary follows a decision tree: Twig is the default → Alpine/DataStar for UI state → Vue for application state.

Files in this skill

  • SKILL.md16.5 KB
  • references/atomic-design.md11.1 KB
  • references/atomic-patterns.md12.3 KB
  • references/auth-account.md17.5 KB
  • references/auth-flows.md16.1 KB
  • references/boilerplate-routing.md14.8 KB
  • references/component-inventory.md11.4 KB
  • references/composition-patterns.md14.5 KB
  • references/element-partials.md6.3 KB
  • references/feeds.md8.4 KB
  • references/headless.md14 KB
  • references/image-presets.md8.1 KB
  • references/javascript-boundaries.md10.9 KB
  • references/multi-site-patterns.md12.7 KB
  • references/plugins/amazon-ses.md2.9 KB
  • references/plugins/blitz.md9.1 KB
  • references/plugins/cache-igniter.md2.8 KB
  • references/plugins/ckeditor.md16 KB
  • references/plugins/colour-swatches.md6.1 KB
  • references/plugins/element-api.md6.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.