---
description: "CodeWiki Frontend pitfalls and review checks"
globs: []
alwaysApply: false
---

# Frontend rules

This track covers more than one language, so no file globs are inferred. Apply these rules manually when they are relevant.

- `transition: all` makes color, size, or position properties added later participate automatically.
  Why: During debugging, it becomes difficult to see which change expanded the animation's scope. Fix: write `transition-property`, or list each property in the shorthand. During review, compare the list with the properties actually changed by the state rules.
  Source: [CSS animations](https://codewiki.com/frontend/css-animation/)
- Applying an ordinary fade-out directly to an element with `display: none` removes it from rendering immediately, so there is no visible exit.
  Why: Cleanup that depends on the corresponding end event may not run either. Fix: separate visual exit from final hiding and complete the hiding directly on the no-animation path. Before adopting `transition-behavior: allow-discrete` and `@starting-style`, verify CSS Transitions Level 2 behavior in your target browsers.
  Source: [CSS animations](https://codewiki.com/frontend/css-animation/)
- Do not assume this is safe: two animations that both write `transform` do not automatically combine translation, scaling, and rotation.
  Why: A later animation can replace the earlier effect, and keyframes can overwrite a component's existing centering transform. Fix: let one animation own the complete `transform`, or put separate effects on nested wrappers. Inspect the element's existing computed transform before adding animation.
  Source: [CSS animations](https://codewiki.com/frontend/css-animation/)
- `animation-fill-mode: forwards` looks as if it saved the endpoint, but it only keeps the animation effect in the cascade after completion.
  Why: Remove the class or override the effect at a higher priority, and the element returns to its ordinary style. Fix: express a persistent endpoint with a class, attribute, or component state. Use fill modes only around delay and active-phase boundaries, not as data-state storage.
  Source: [CSS animations](https://codewiki.com/frontend/css-animation/)
- JavaScript that commits business state only after `transitionend` or `animationend` can stall when duration is zero, no animation is generated, the animation is canceled, or the element is removed.
  Why: Multiple properties also produce multiple transition-end events. Fix: commit business state first and treat the end event as a visual-cleanup signal. Filter by property or animation name, provide a timeout or immediate path, and test reduced motion and rapid reversal.
  Source: [CSS animations](https://codewiki.com/frontend/css-animation/)
- Do not assume this is safe: using `translateZ(0)` or leaving `will-change` in place to “force the GPU” is not a stable performance guarantee.
  Why: Browsers choose layer promotion, and extra layers can consume memory and add compositing work. Fix: prefer properties that normally avoid layout work, then verify them with performance tools on a target device. Use `will-change` briefly only when measurement shows a benefit, and remove it after the effect.
  Source: [CSS animations](https://codewiki.com/frontend/css-animation/)
- A text item can still push through the container after you set `flex-shrink: 1`.
  Why: The usual cause is the automatic minimum size, which stops it from shrinking below its min-content size. Fix: set `min-inline-size: 0` only on the item whose content may shrink, then decide whether long words, URLs, or code should wrap, clip, or scroll. Do not add `overflow: hidden` to the whole component blindly; it can clip focus outlines and popovers.
  Source: [CSS flexbox](https://codewiki.com/frontend/css-flexbox/)
- Do not assume this is safe: giving every item `flex: 1` does not necessarily produce equal outer widths.
  Why: Automatic minimums, different padding or borders, explicit minimums, and unbreakable content can all change the result. Fix: decide whether the content boxes or border boxes must be equal, then normalize `box-sizing` and box-model inputs. Use a zero `flex-basis` when content bases should not differ, inspect minimum sizes, and measure the final border boxes with representative content.
  Source: [CSS flexbox](https://codewiki.com/frontend/css-flexbox/)
- `justify-content` often appears to do nothing because there is no positive main-axis free space, or because an `auto` margin has already absorbed it.
  Why: Alignment cannot create space while items are shrinking or overflowing. Fix: inspect the container's main size, final item sizes, `gap`, and margins in developer tools. Resolve sizing and overflow first, then choose how `justify-content` distributes what remains.
  Source: [CSS flexbox](https://codewiki.com/frontend/css-flexbox/)
- Do not assume this is safe: `align-content` does not center items within one line.
  Why: Changing it usually has no visible effect when the container does not wrap, creates only one flex line, or has no extra cross-axis space. Fix: use `align-items` within a line and `align-self` for an exceptional item. Use `align-content` only to distribute cross-axis space between multiple flex lines.
  Source: [CSS flexbox](https://codewiki.com/frontend/css-flexbox/)
- Do not assume this is safe: `order`, `row-reverse`, and `column-reverse` change visual positions without synchronizing the DOM, speech, or sequential focus order.
  Why: The left-to-right screen order can oppose the order produced by the Tab key. Fix: make DOM order match the reading and interaction logic. Reserve visual reordering for changes that do not alter meaning, and test every responsive breakpoint with a keyboard and screen reader.
  Source: [CSS flexbox](https://codewiki.com/frontend/css-flexbox/)
- Do not treat `1fr` as “divide unconditionally” lets long content force the container wider.
  Why: A track's automatic minimum can still use the item's min-content contribution.
  Source: [CSS grid](https://codewiki.com/frontend/css-grid/)
- Adding `gap` to `repeat(3, 33.333%)` usually exceeds the container because the percentage tracks already consume nearly all available width and the gutters are added afterward.
  Source: [CSS grid](https://codewiki.com/frontend/css-grid/)
- `grid-auto-flow: dense` may place a later item in an earlier hole.
  Why: Screen order changes, but DOM, reading, and sequential focus order normally do not follow it.
  Source: [CSS grid](https://codewiki.com/frontend/css-grid/)
- A leftover `grid-column: 2` or `1 / 4` can create implicit columns after a responsive template changes to one column.
  Why: Generated code often edits the container template but forgets to reset item placement.
  Source: [CSS grid](https://codewiki.com/frontend/css-grid/)
- Do not assume this is safe: if rows in `grid-template-areas` have different cell counts or a repeated name is not rectangular, the browser drops the entire declaration.
  Why: A spelling mismatch can also disconnect an item's `grid-area` from the template.
  Source: [CSS grid](https://codewiki.com/frontend/css-grid/)
- Creating a styled component inside another component's render path creates a new component identity on repeated renders in runtime systems that expose a `styled` factory.
  Source: [CSS-in-JS](https://codewiki.com/frontend/css-in-js/)
- Interpolating mouse coordinates, animation progress, or arbitrary colors into rules can create a growing collection of nearly identical classes.
  Source: [CSS-in-JS](https://codewiki.com/frontend/css-in-js/)
- Generated wrappers often pass `variant`, `isOpen`, or theme-only props through to a native element even though those fields exist only to choose styles.
  Source: [CSS-in-JS](https://codewiki.com/frontend/css-in-js/)
- Do not assume this is safe: hashing a class name prevents an accidental name match, but global selectors, cascade layers, specificity, inheritance, and source order still affect the element.
  Source: [CSS-in-JS](https://codewiki.com/frontend/css-in-js/)
- A server can emit correct HTML while omitting used rules, duplicating them on hydration, or assigning different generated identifiers on the client.
  Source: [CSS-in-JS](https://codewiki.com/frontend/css-in-js/)
- Build-time tools cannot extract arbitrary values assembled through dynamic property names, uncontrolled function calls, or source files excluded from their scanner.
  Source: [CSS-in-JS](https://codewiki.com/frontend/css-in-js/)
- Do not treat client validation as a security check lets a direct request bypass every rule.
  Why: DOM attributes, JavaScript, and hidden fields are all controlled by the client.
  Source: [Form validation](https://codewiki.com/frontend/form-validation/)
- After `setCustomValidity()` receives one non-empty message, the control stays invalid even when the user fixes the input.
  Why: Changing text in a page-level `` does not change native validity state.
  Source: [Form validation](https://codewiki.com/frontend/form-validation/)
- Do not assume this is safe: adding `novalidate` or canceling `invalid` without equivalent feedback creates a form that fails silently or submits bad data directly.
  Source: [Form validation](https://codewiki.com/frontend/form-validation/)
- Showing an error or starting a remote request on every keystroke reports problems before the user finishes and can produce out-of-order results with stale messages.
  Source: [Form validation](https://codewiki.com/frontend/form-validation/)
- Programmatic tests can create false confidence.
  Why: `form.submit()` bypasses constraint validation, while script-assigned values do not exercise `minlength` and `maxlength` checks the same way as user-provided input.
  Source: [Form validation](https://codewiki.com/frontend/form-validation/)
- Do not assume this is safe: adding a click listener and button styles to a `` does not give it button keyboard operation, focus rules, disabled state, or assistive-technology semantics.
  Source: [Frontend development foundations](https://codewiki.com/frontend/getting-started/)
- Giving the main container a fixed width or recreating a screenshot with absolute positioning produces overlap and horizontal scroll when text grows, zoom increases, or the viewport narrows.
  Source: [Frontend development foundations](https://codewiki.com/frontend/getting-started/)
- Using `innerHTML` to insert a name or status string parses that string as markup.
  Why: If the data comes from a URL, form, or API, the call can become a cross-site scripting entry point.
  Source: [Frontend development foundations](https://codewiki.com/frontend/getting-started/)
- Do not assume this is safe: writing navigation as an element whose click calls `location`, or removing a form's `action` and relying entirely on script, removes the baseline capability when loading, execution, or assistive-technology paths fail.
  Source: [Frontend development foundations](https://codewiki.com/frontend/getting-started/)
- Do not assume this is safe: adding a framework, state library, and complex build configuration before building one static page expands the failure surface without automatically improving semantics, layout, or accessibility.
  Source: [Frontend development foundations](https://codewiki.com/frontend/getting-started/)
- Do not assume this is safe: labeling `768px` as the “tablet breakpoint” and assuming touch on one side and a mouse on the other confuses device categories with layout constraints.
  Why: A split desktop window can be narrow, and a tablet can have a precise pointer. Fix: derive breakpoints from real content failures. Test input with `hover`, `pointer`, and a keyboard separately instead of inferring capabilities from viewport width.
  Source: [Responsive web design](https://codewiki.com/frontend/responsive-design/)
- Do not assume this is safe: `width: 100vw` ignores an element's container and may include the vertical scrollbar in its box.
  Why: `height: 100vh` can also hide content as mobile browser chrome expands and collapses. Fix: prefer `width: auto` or `100%` for ordinary blocks. When something truly fills viewport height, choose the stable small viewport unit `svh` or the chrome-responsive `dvh` deliberately, and keep content scrollable.
  Source: [Responsive web design](https://codewiki.com/frontend/responsive-design/)
- A Flex or Grid item can overflow even when its track uses `1fr`, because a long URL, table, or preformatted block contributes a large automatic minimum size.
  Why: Fix: use `minmax(0, 1fr)` for tracks that should shrink and set `min-width: 0` on the item when necessary. Give real long content an explicit wrapping or local-scrolling policy as well.
  Source: [Responsive web design](https://codewiki.com/frontend/responsive-design/)
- Using `order`, grid coordinates, or `grid-auto-flow: dense` to create an attractive narrow layout can make visual order diverge from DOM reading order and sequential keyboard focus.
  Why: Fix: write the DOM in a meaningful reading order first. Let layout switches change geometry only. If the task order truly differs, revisit the document structure instead of masking it with CSS.
  Source: [Responsive web design](https://codewiki.com/frontend/responsive-design/)
- A `srcset` can list several image candidates while `sizes` still claims the image is always `100vw`.
  Why: The browser may then choose a resource much wider than the actual column, and shrinking it with CSS does not undo that request. Fix: keep `sizes` synchronized with final layout conditions, then inspect network requests and rendered size on both sides of each breakpoint. Use `picture` for different compositions and same-content candidates for resolution choices.
  Source: [Responsive web design](https://codewiki.com/frontend/responsive-design/)
- Older tutorials often use `@import`, `map-get()`, `darken()`, and other global names.
  Why: Dart Sass has deprecated `@import` and global built-in functions, which also place members in a hard-to-trace global namespace.
  Source: [Sass](https://codewiki.com/frontend/sass/)
- `$brand` is a concrete value after compilation.
  Why: JavaScript can't change it in an already loaded page, and a DOM ancestor can't override it through the cascade.
  Source: [Sass](https://codewiki.com/frontend/sass/)
- Generated code often nests `.page .sidebar .card .title` to match a template.
  Why: The output selector now depends on those containers and has higher specificity, so moving the component can break it.
  Source: [Sass](https://codewiki.com/frontend/sass/)
- A mixin emits content at every call site, and a loop emits rules for every iteration.
  Why: A short source file can therefore grow into repeated declarations and unused utility classes.
  Source: [Sass](https://codewiki.com/frontend/sass/)
- `map.get()` returns `null` for a missing key.
  Why: Passing that result into a color or number function can cause a remote, cryptic build error; some declarations disappear when their value is `null`.
  Source: [Sass](https://codewiki.com/frontend/sass/)
- A `` with a click listener implements only the mouse path when used as a button.
  Why: It has no button role, sequential focus, Enter and Space activation, disabled state, or form behavior by default.
  Source: [Semantic HTML](https://codewiki.com/frontend/html-semantic-tags/)
- Turning every layout wrapper into `` or `` creates false sections with no theme or heading.
  Why: More tags do not produce stronger semantics.
  Source: [Semantic HTML](https://codewiki.com/frontend/html-semantic-tags/)
- Redundant or conflicting ARIA on native elements can erase their capabilities.
  Why: An incompatible role on ``, or `role="banner"` on every article header, gives assistive technology a false model.
  Source: [Semantic HTML](https://codewiki.com/frontend/html-semantic-tags/)
- Do not depend on the abandoned HTML outline algorithm; doing so makes every nested section start with ``.
  Why: Mainstream browsers do not infer a usable heading hierarchy from `` depth.
  Source: [Semantic HTML](https://codewiki.com/frontend/html-semantic-tags/)
- Describing semantic elements as an SEO ranking shortcut turns a verifiable structural benefit into an unsupported search promise.
  Why: Structured data, page quality, and HTML semantics are separate mechanisms.
  Source: [Semantic HTML](https://codewiki.com/frontend/html-semantic-tags/)
- Do not assume this is safe: `` `bg-${tone}-600` `` looks as though it will produce valid classes, but source detection doesn't execute template strings and never sees the complete candidates.
  Why: A rule contributed accidentally by another file in development can also hide the bug until a production entry or shared package builds alone.
  Source: [Tailwind CSS](https://codewiki.com/frontend/tailwind-css/)
- `sm:` isn't the default phone range, and `md:` doesn't cover only one kind of tablet.
  Why: They are minimum-width conditions active from theme breakpoints upward; writing only `sm:text-sm` leaves narrower widths without that font-size utility.
  Source: [Tailwind CSS](https://codewiki.com/frontend/tailwind-css/)
- A `div` with `cursor-pointer` still lacks button semantics, and `focus:outline-none` can remove the only visible focus indicator.
  Why: Utilities can only change presentation; they can't supply button roles, keyboard activation, disabled semantics, or accessible names.
  Source: [Tailwind CSS](https://codewiki.com/frontend/tailwind-css/)
- Do not assume the second class in `px-4 px-8` must win confuses HTML string order with CSS rule order.
  Why: Tailwind's generated stylesheet ordering and the cascade decide the result; merging two component class sets also makes the intended conflict unclear.
  Source: [Tailwind CSS](https://codewiki.com/frontend/tailwind-css/)
- A collection of `mt-[13px]`, `text-[#17324d]`, and near-duplicate widths bypasses shared tokens.
  Why: The code still compiles, but reviewers can't tell which differences are intentional and which are random generated choices.
  Source: [Tailwind CSS](https://codewiki.com/frontend/tailwind-css/)
- Older answers commonly recommend `npx tailwindcss init -p`, a `content` array, and `@tailwind base; @tailwind components; @tailwind utilities;`.
  Why: That isn't the current default Vite workflow for Tailwind CSS 4, and copying it can produce missing commands, wrong dependencies, or inert configuration.
  Source: [Tailwind CSS](https://codewiki.com/frontend/tailwind-css/)
