mcpField
P
pseudo-elements

pseudo-elements

github.com/raphaelsalajaDesign & UI936139 installsUpdated 33w ago
Repository

About pseudo-elements

pseudo-elements is a code-review skill for checking CSS and JavaScript against pseudo-element, View Transitions API, and native styling practices. It is intended for developers who want file-and-line findings plus a rule-count summary.

Key features

  1. 01Checks pseudo-element content and layering
  2. 02Reviews View Transitions naming and cleanup
  3. 03Checks native backdrop, placeholder, and selection styling
  4. 04Reports findings with file and line numbers
  5. 05Includes rule counts and severity summary

Use cases

  1. 01Reviewing CSS for ::before and ::after issues
  2. 02Checking View Transitions API implementations
  3. 03Finding custom DOM used for decorative styling

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/raphaelsalaja/userinterface-wiki --skill pseudo-elements

After installing, type/pseudo-elementsin Claude Code to confirm it loaded.

Details

From the project README

Pseudo Elements

Review CSS and JavaScript for pseudo-element best practices and View Transitions API usage.

How It Works

  1. Read the specified files (or prompt user for files/pattern)
  2. Check against all rules below
  3. Output findings in file:line format

Rule Categories

PriorityCategoryPrefix
1Before/Afterpseudo-
2View Transitionstransition-
3Native Stylingnative-

Rules

Before/After Rules
pseudo-content-required

::before and ::after require content property to render.

Fail:

.button::before {
  position: absolute;
  background: var(--gray-3);
}

Pass:

.button::before {
  content: "";
  position: absolute;
  background: var(--gray-3);
}
pseudo-over-dom-node

Use pseudo-elements for decorative content instead of extra DOM nodes.

Fail:

<button className={styles.button}>
  <span className={styles.background} /> {/* Unnecessary DOM node */}
  Click me
</button>

Pass:

<button className={styles.button}>
  Click me
</button>
.button::before {
  content: "";
  /* decorative background */
}
pseudo-position-relative-parent

Parent must have position: relative for absolute pseudo-elements.

Fail:

.button::before {
  content: "";
  position: absolute;
  inset: 0;
}
/* .button has no position */

Pass:

.button {
  position: relative;
}

.button::before {
  content: "";
  position: absolute;
  inset: 0;
}
pseudo-z-index-layering

Pseudo-elements need z-index to layer correctly with content.

Fail:

.button::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gray-3);
}
/* Covers button text */

Pass:

.button {
  position: relative;
  z-index: 1;
}

.button::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gray-3);
  z-index: -1;
}
pseudo-hit-target-expansion

Use negative inset values to expand hit targets without extra markup.

Fail:

<div className={styles.wrapper}> {/* Extra wrapper for hit target */}
  <a className={styles.link}>Link</a>
</div>

Pass:

.link {
  position: relative;
}

.link::before {
  content: "";
  position: absolute;
  inset: -8px -12px;
}
View Transitions Rules
transition-name-required

Elements participating in view transitions need view-transition-name.

Fail:

document.startViewTransition(() => {
  // No view-transition-name assigned
  targetImg.src = newSrc;
});

Pass:

sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
  sourceImg.style.viewTransitionName = "";
  targetImg.style.viewTransitionName = "card";
});
transition-name-unique

Each view-transition-name must be unique on the page during transition.

Fail:

.card {
  view-transition-name: card;
}
/* Multiple cards with same name */

Pass:

// Assign unique name only to transitioning element
element.style.viewTransitionName = `card-${id}`;
transition-name-cleanup

Remove view-transition-name after transition completes.

Fail:

sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
  targetImg.style.viewTransitionName = "card";
});
// sourceImg still has name, causes conflict on next transition

Pass:

sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
  sourceImg.style.viewTransitionName = "";
  targetImg.style.viewTransitionName = "card";
});
transition-over-js-library

Prefer View Transitions API over JavaScript animation libraries for page transitions.

Fail:

import { motion } from "motion/react";

function ImageLightbox() {
  return (
    <motion.img layoutId="hero" /> // JS-based shared element transition
  );
}

Pass:

function openLightbox(img: HTMLImageElement) {
  img.style.viewTransitionName = "hero";
  document.startViewTransition(() => {
    // Native browser transition
  });
}
transition-style-pseudo-elements

Style view transition pseudo-elements for custom animations.

Fail:

document.startViewTransition(() => { /* ... */ });
// Uses default crossfade

Pass:

::view-transition-group(card) {
  animation-duration: 300ms;
  animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
Native Styling Rules
native-backdrop-styling

Use ::backdrop pseudo-element for dialog/popover backgrounds.

Fail:

<>
  <div className={styles.overlay} onClick={close} />
  <dialog className={styles.dialog}>{children}</dialog>
</>

Pass:

dialog::backdrop {
  background: var(--black-a6);
  backdrop-filter: blur(4px);
}
native-placeholder-styling

Use ::placeholder for input placeholder styling, not wrapper elements.

Fail:

<div className={styles.inputWrapper}>
  {!value && <span className={styles.placeholder}>Enter text...</span>}
  <input value={value} />
</div>

Pass:

input::placeholder {
  color: var(--gray-9);
  opacity: 1;
}
native-selection-styling

Use ::selection for text selection styling.

Pass:

::selection {
  background: var(--blue-a5);
  color: var(--gray-12);
}

Output Format

When reviewing files, output findings as:

file:line - [rule-id] description of issue

Example:
components/button/styles.module.css:12 - [pseudo-content-required] ::before missing content property
components/lightbox/index.tsx:45 - [transition-over-js-library] Using motion layoutId instead of View Transitions API

Summary Table

After findings, output a summary:

RuleCountSeverity
pseudo-content-required2HIGH
pseudo-over-dom-node1MEDIUM
transition-name-cleanup1MEDIUM

References

Comments

Markdown supported