Skip to content

The Webflow rulebook

Full rules for AI

The complete rules, word for word, exactly as HTFlow gives them to an AI before it writes a section. Copy them into ChatGPT, Claude or any other tool to get Webflow-ready code from it too.

How to use this page

The other pages in this chapter explain each rule in plain words. This page is the raw text the AI actually reads — the rules HTFlow briefs the Site Agent and MCP clients such as Claude with (an MCP client can also fetch them with get_flow_webflow_rules). It is read straight from HTFlow's code, so it is always the current version.

It comes in three parts, in the order an AI should read them. Later parts override earlier ones where they disagree.

1. The Webflow rulebook

The full HTML, CSS and JavaScript rulebook. It was written for every HTFlow builder, so it also mentions Liquid tags such as {% style %} — on Flow sites, part 2 overrides those parts.

markdown
## Mandatory Webflow HTML, CSS & JavaScript Rules for HTFlow

### Absolute Prohibitions
- NEVER use CSS frameworks (Tailwind, Bootstrap) or JS libraries (jQuery, React, GSAP). Vanilla only.
- NEVER use CSS shorthand. EXCEPTION: overflow must stay shorthand (overflow: hidden).
- NEVER use the outline properties at all — see Interactive States for the box-shadow focus ring.
- NEVER use background-image for imagery — use <img> with absolute positioning.
- NEVER use pseudo-ELEMENTS: ::before, ::after, ::first-line, ::marker. Render that content as real markup.
  This does NOT restrict pseudo-CLASSES — see the state rules below.
- NEVER use external CSS/JS files or CDN dependencies. Everything is self-contained.
- NEVER use breakpoints other than 991px, 767px and 479px.
- NEVER use class or id selectors in JavaScript.
- NEVER use getElementById / getElementsByClassName / getElementsByTagName.
- NEVER use 'var' — const/let only.
- NEVER use function declarations — arrow functions only.
- NEVER use emojis — inline SVG only.
- NEVER use ul/li lists — use div-based flex/grid layouts.
- NEVER use inline event handlers (onclick, onload, onerror).
- NEVER use inline styles, except temporary ones set by JS at runtime.

### Mandatory Requirements
- ALWAYS use data-ht-* attributes for ALL DOM selection.
- ALWAYS use longhand CSS properties (margin-top, margin-right, …).
- ALWAYS give every styled element its own descriptive class name.
- ALWAYS use semantic HTML with proper alt and aria-* attributes.
- ALWAYS use modern ES6+ JavaScript.
- ALWAYS use CSS Grid with grid-template-rows: 1fr when using grid-template-columns.
- ALWAYS give interactive elements :hover and :focus-visible states in CSS.

### Section Structure (HTFlow raw Liquid)
- One root <section> element carrying the section's BEM block class (e.g. <section class="hero">).
  That root IS the wrapper — do NOT add an htflow-wrapper div.
- No <!DOCTYPE>, <html>, <head> or <body> tags. A section is a fragment.
- CSS goes in the section's {% style %} block (the section equivalent of <style data-ht-styles>).
- JS goes in the section's {% javascript %} block (the section equivalent of <script data-ht-main-script>).
- BEM naming: block, block__element, block--modifier (e.g. .hero__title, .features__card--highlighted).
- All class names inside the section must follow that section's BEM block.
- Reuse the same container class across sections (e.g. container-large) for consistent page rhythm.

### HTML Rules
- Use semantic elements (<header>, <nav>, <main>, <section>, <article>, <aside>, <footer>).
- Use <button> for clicks, <a> for links, <img> with alt for images.
- Every element that is styled or scripted must have a class name; never use ids for styling or JS.
- Use foreground <img> with position: absolute + object-fit: cover instead of CSS background images.
- Images from Unsplash only (https://images.unsplash.com/...).
- Use inline SVG for every icon. No emoji characters anywhere in markup.
- Bind behaviour through data-ht-* attributes, not classes.

### CSS Rules
- Longhand only: margin-top/right/bottom/left, padding-*, border-width/style/color, etc.
  Correct:   margin-top: 20px; margin-bottom: 20px; border-width: 1px; border-style: solid; border-color: #ccc;
  Forbidden: margin: 20px 0; border: 1px solid #ccc;
- Grid must declare grid-template-rows: 1fr whenever grid-template-columns is used.
- All selectors scoped to the section's BEM block class — no body, html, * or unscoped tag selectors.
- Only Webflow breakpoints: @media (max-width: 991px) tablet, 767px mobile landscape, 479px mobile portrait.
- Breakpoint styles: prefer the named block over a hand-written media query.
    {% breakpoint tablet %}
    .block__el { grid-template-columns: 1fr; }
    {% endbreakpoint %}
  Names: tablet (991px), mobile-landscape (767px), mobile (479px). The renderer
  expands each block to its media query, so Liquid inside works as it does
  anywhere else. One block per breakpoint — the editor writes into the same
  block, so scattering the same breakpoint over several blocks or shells makes
  the Class manager show it as several groups.
  Raw @media still works and is required for anything a block cannot express:
  @supports, @container, print, (hover: hover), prefers-reduced-motion, and
  min-width (mobile-first) queries.
- Relative units (rem, em) for typography.

### Interactive States (required)
- State pseudo-CLASSES are expected, not restricted: :hover, :focus, :focus-visible, :active, :disabled,
  and structural ones like :nth-child. Only pseudo-ELEMENTS (::before/::after) are forbidden.
- Every button, link, card and other clickable element MUST have a visible :hover state, written in CSS:
    .hero__cta { background-color: #111; transition-property: background-color; transition-duration: .2s; }
    .hero__cta:hover { background-color: #333; }
- Every interactive element MUST also have a :focus-visible state for keyboard users. Never remove the
  focus ring without replacing it.
- NEVER use outline, outline-width, outline-style, outline-color or outline-offset. Webflow draws its
  own selection outline on the canvas and an authored one fights it. Draw focus rings with box-shadow:
    .hero__cta:focus-visible { box-shadow: 0 0 0 2px #111; }
  box-shadow paints the same ring, follows border-radius, and leaves the canvas alone.
- Hover on a parent that restyles a child is fine: .card:hover .card__title { color: #6cf; }
- Keep state changes to CSS. Use JavaScript only for motion CSS cannot express (scroll-driven reveals,
  sequenced timelines, pointer-tracking) — not for ordinary hover or focus styling.

### JavaScript Rules
- Vanilla ES6+. Wrap in an arrow IIFE to avoid global pollution: (() => { ... })();
- Arrow functions only — no function declarations, no function expressions.
- const/let only, never var.
- Select exclusively through data-ht-* attributes:
  Correct:   document.querySelectorAll('[data-ht-button]').forEach((button) => { … });
  Forbidden: document.querySelectorAll('.button'), document.getElementById('button')
- Read values from dataset (target.dataset.htData), not getAttribute.
- Never use classList.add/remove/toggle for state — use data-state, data-open, aria-expanded or aria-hidden
  so the Webflow canvas keeps rendering the element correctly.
- Maintain aria-expanded / aria-hidden / aria-current for accessibility.
- Use requestAnimationFrame for animation loops.

### Animation Opacity Rules
- NEVER set opacity: 0 directly in CSS for animation elements (it makes them invisible on the Webflow canvas).
- Use a data-ht-animate attribute + JS to set opacity 0 at runtime on DOMContentLoaded,
  then animate in on scroll via IntersectionObserver.

### Form Rules (Webflow Export)
- Always put spaces between attributes: <input type="text" id="name" name="name">
- Checkboxes: wrap each <input type="checkbox"> in <div data-wf-checkbox>.
- Radio buttons: wrap each <input type="radio"> in <div data-wf-radio>.
- Submit button: <button type="submit" data-wait="Please wait...">Send</button>
- Success/error messages: <div data-wf-success>...</div> and <div data-wf-error>...</div>
- Select: <select id="topic" name="topic"><option value="">Select...</option></select>
- Form tag: <form name="contact-form" id="contact-form" method="post" class="contact-form" data-ht-form>


### Mandatory Usage & Regeneration Instructions
- Every rule above is MANDATORY for Webflow mode HTML, CSS, and JS generation.
- Apply these rules strictly across the entire generation process.
- Section writes are machine-checked. A violation rejects the write with
  HTFLOW_WEBFLOW_RULES_VIOLATED and the section is NOT saved.
- If any conflict, doubt, or rule violation occurs at any point, REGENERATE the section
  HTML, CSS, and JS immediately to strictly satisfy these Webflow rules.
- These are compatibility rules, not visual-design rules; the user's request controls the design.

2. The Flow site contract

What changes for Flow sites. Where it disagrees with part 1, this part wins.

text
------------------------------------------------------------
HTFLOW FLOW SITE CONTRACT — OVERRIDES SECTION STRUCTURE ABOVE
------------------------------------------------------------
This request targets the HTFlow Flow builder, not the Liquid builder or browser extension.

- Return one root <section> fragment. Do not return document-level html/head/body tags and do not add an outer wrapper div.
- Put the section CSS inside the response's single <style> tag. HTFlow stores it separately from the HTML.
- Put optional section JavaScript inside the response's single <script> tag. HTFlow stores it separately from the HTML.
- Never emit Liquid tags or a schema block.
- Use BEM class naming and scope every CSS selector to the section's BEM block.
- Use longhand CSS only; overflow is the sole shorthand exception.
- Only 991px, 767px and 479px responsive breakpoints are allowed, written as plain @media (max-width: …). {% breakpoint %} blocks are Liquid and do not exist here.
- Use a real foreground <img> for imagery, never background-image.
- Do not use pseudo-elements, inline styles, inline handlers, external scripts/styles, frameworks, emoji, ul/ol, var, or function declarations.
- Every scripted target must use a data-ht-* attribute. JavaScript selectors must not use classes or ids.
- Use const/let, arrow functions and an arrow IIFE. Drive state through data/aria attributes, never classList.
- The site's global header and footer always wrap a page's own sections. Do not build a header or footer into a page section, and do not try to position sections around them.
- Every interactive element needs visible :hover and :focus-visible styles. Draw the focus ring with box-shadow — the outline properties are not allowed.
- If a CSS grid declares grid-template-columns, it must also declare grid-template-rows: 1fr. A breakpoint override of the same selector inherits it.
- CSS must not set opacity: 0 for animation. Apply the initial hidden state from JavaScript at runtime.

3. The design system contract

How every section stays on the site's design: colours, fonts, sizes and spacing come from the site's tokens. It overrides the example values in part 1.

text
DESIGN SYSTEM — enforced: a write that breaks it is refused. It overrides every typed-out example value in the Webflow rules (#111, 20px and the like are illustrations).
- Every colour, font family, font size, spacing (margin/padding/gap), border radius and shadow comes from the site's tokens: write var(--name). Typed-out values are refused; 0, auto and percentages for radius are fine. Layout (widths, grids, positions, weights, line heights) is free.
- Define the whole vocabulary before the first section with set_flow_design_tokens: colours (text, muted, background, surface, accent, accent-contrast, border), font families (body, heading), a font-size scale (e.g. text-sm, text-base, text-lg, heading-sm … display), a spacing scale (e.g. space-2xs … space-3xl), radii and shadows.
- Shared components live in the site stylesheet (set_flow_site_css): buttons, containers, section headings, eyebrows, cards. One class each; variants as combo classes (.button.is-secondary). Sections use these classes as they are and never restyle them.
- Before designing, read get_flow_style_guide: every token and the shared class names, in a few hundred tokens instead of reading other sections.
- Use a token only if it exists. SVG icons use currentColor.

Explained in plain words

Every rule above, with the reason behind it and an everyday comparison: HTML, CSS, JavaScript and Forms.