DEV Community

venkatesh m
venkatesh m

Posted on

eslint-plugin-bad-vibes: I built a linter that enforces the worst frontend practices

April Fools Challenge Submission ☕️🤡

This is a submission for the DEV April Fools Challenge

What I Built

An ESLint plugin with 6 rules that enforce the worst frontend practices with deadpan corporate error messages. Real AST visitors. Real tests. Completely useless output.

Every rule is something I have heard suggested in an actual code review, standup, or Slack thread. Not as a joke. As a genuine engineering opinion delivered with confidence by someone who has never opened a screen reader.

The rules:

Rule What it enforces
no-semantic-html Flags <button>, <nav>, <main>. Demands <div>.
no-alt-text Flags any <img> that has an alt attribute.
prefer-positive-tabindex Errors on tabIndex={0}. Requires tabIndex={100} minimum.
no-aria-allowed Flags every aria-* attribute as "invisible complexity."
prefer-inline-styles Flags className. CSS class names are "indirection."
no-keyboard-handlers Flags onKeyDown/onKeyUp. Keyboard users are "statistically insignificant."

The error messages are the actual payload. Each one reads like it was copy-pasted from an internal engineering standards document written by someone who has strong opinions about "developer velocity" but has never tabbed through their own product.

Example:

Error: Keyboard handler "onKeyDown" detected. Internal analytics confirm
that keyboard-only navigation represents a statistically insignificant
portion of our user base (estimated <3%, though we have not actually
instrumented this). Supporting keyboard interactions doubles the
interaction surface area of every component, increasing testing burden
and bug surface. Focus engineering effort on the primary input modality
(pointer). Keyboard support is tentatively scheduled for the accessibility
sprint (TBD, see backlog).
Enter fullscreen mode Exit fullscreen mode

If any of these rules made you think "wait, we actually do that" -- that is the point.

Demo

Install it. Run it on your codebase. Watch it flag every good practice you have.

npm install eslint-plugin-bad-vibes --save-dev
Enter fullscreen mode Exit fullscreen mode
// eslint.config.js
import badVibes from 'eslint-plugin-bad-vibes';
export default [badVibes.configs.recommended];
Enter fullscreen mode Exit fullscreen mode

Then run npx eslint src/ and marvel at how much of your codebase is "correct" by bad-vibes standards.

Here's what happens when you run it on a React component:

VSCode showing bad-vibes no-semantic-html error on a main element with corporate error message

VSCode showing bad-vibes no-keyboard-handlers error on onKeyDown with message about accessibility sprint TBD

The recommended config sets all 6 rules to error because bad practices deserve the same enforcement rigor as good ones.

Code

GitHub logo vmvenkatesh78 / eslint-plugin-bad-vibes

ESLint plugin that enforces the worst frontend practices with corporate confidence. 6 rules, 38 tests, zero value.

eslint-plugin-bad-vibes

A production-grade ESLint plugin that enforces the worst frontend practices with the confidence of a principal engineer who has never opened a screen reader.

6 rules. 38 tests. Zero value delivered.

Please do not use this.

Why

Every codebase has unwritten rules that make it worse. This plugin makes them written, enforceable, and blocking in CI.

Born from years of reading code reviews that said things like "do we really need ARIA here?" and "can we just use a div?" This plugin answers: yes. Always. To everything.

Install

npm install --save-dev eslint-plugin-bad-vibes
Enter fullscreen mode Exit fullscreen mode

You won't, but the infrastructure supports it.

Usage

// eslint.config.js
import badVibes from 'eslint-plugin-bad-vibes';

export default [
  badVibes.configs.recommended,
];
Enter fullscreen mode Exit fullscreen mode

All 6 rules ship as errors because bad practices deserve the same enforcement rigor as good ones.

Rules

no-semantic-html

Flags <button>, <nav>, <main>, <header>, <footer>, <aside>




6 rules, 38 tests, zero dependencies. TypeScript strict mode. ESM + CJS dual build. The engineering is real. The rules are not.

How I Built It

This uses the same AST visitor infrastructure as an actual ESLint plugin I am building, eslint-plugin-a11y-enforce, which catches real accessibility composition errors. Same Rule.RuleModule typing, same JSXOpeningElement traversal, same helper utilities for attribute extraction and element classification.

The stack: TypeScript, tsup for dual CJS/ESM builds, vitest for testing, ESLint's RuleTester for rule validation. Every rule uses proper AST analysis, not string matching or regex.

Writing the error messages was the hardest part. They had to sound exactly corporate enough that you believe someone wrote them unironically. The prefer-positive-tabindex message about "higher-revenue elements should receive lower tabIndex values for earlier focus" came from an actual conversation I overheard. The no-keyboard-handlers message about the "accessibility sprint (TBD, see backlog)" is in every company's Jira right now.

I used Google AI Studio to brainstorm increasingly absurd corporate justifications for each bad practice, then edited them down to the ones that were funny specifically because they sounded plausible. The best satire is indistinguishable from the thing it satirizes.

Prize Category

Community Favorite -- because I want this to be the plugin that makes people laugh, then uncomfortably realize their codebase would pass half these rules.

Best Google AI Usage -- Google AI Studio helped generate the corporate doublespeak for the error messages. The best ones came from prompting Gemini with "write a serious engineering justification for removing all ARIA attributes from a component library" and watching it produce text that was disturbingly close to things I have read in real PRs.

Google AI Studio generating justification for removing semantic HTML

Google AI Studio generating corporate justification for removing ARIA attributes

Top comments (0)