npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@smartive/eslint-config

v10.0.0

Published

ESLint configuration by smartive

Readme

@smartive/eslint-config

This package provides smartive's default eslint configuration.

Installation

$ npm install eslint @smartive/eslint-config -D

Requires ESLint 10.0.0 or newer — see ESLint 10 is required.

Usage

This package offers three different rule sets, one for plain TypeScript applications, a separate one for React applications and one that works well with Next.js applications (minimum supported version is Next.js v16).

Flat Config (eslint.config.mjs)

import { config } from '@smartive/eslint-config'

// For plain TS applications ..
export default config('typescript');

// .. or React applications
export default config('react');

// .. or Next.js applications
// make sure to add `@next/eslint-plugin-next@16`
// to your devDependencies
export default config('nextjs');

NPM scripts

To use eslint add the following to your package.json:

"scripts": {
  "lint": "eslint {your source directory}",
  "lint:fix": "eslint {your source directory} --fix"
}

Included plugins

eslint-config-next, eslint-plugin-react, eslint-plugin-react-hooks, eslint-plugin-import and eslint-plugin-jsx-a11y are no longer used.

ESLint 10 is required

@eslint-react/eslint-plugin dropped ESLint 9 in its v3.0.0, which declares a ^10.0.0 peer range. Note that its peerDependencies say eslint: "*", so npm will not warn you about an older ESLint — it will simply misbehave at some point.

Next.js without eslint-config-next

eslint-config-next does not work on ESLint 10: it bundles eslint-plugin-react, whose rules all throw while loading because React version detection calls the context.getFilename() API that ESLint 10 removed, and it parses plain JavaScript with a Babel parser that calls the removed scopeManager.addGlobals() (vercel/next.js#89764). This package therefore rebuilds what it provides from ESLint 10 compatible parts, split by where each part makes sense:

| From eslint-config-next/core-web-vitals | Here | Rule set | | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------- | | 6 jsx-a11y rules, all warn | eslint-plugin-jsx-a11y-x's recommended preset, all error — see Accessibility rules | react | | import/no-anonymous-default-export | import-x/no-anonymous-default-export | react | | Babel parser, JSX in .js | the typescript-eslint parser, with JSX enabled in .js, .jsx and .mjs | react | | eslint-plugin-react, eslint-plugin-react-hooks | ESLint React (see below for what it does not cover) | react | | @next/next rules, core-web-vitals severities | @next/eslint-plugin-next, taken from its own core-web-vitals config | nextjs | | jsx-a11y/alt-text also checking <Image> | the same option | nextjs | | ignores .next/, out/, build/, next-env.d.ts | the same ignores | nextjs |

The accessibility rules are named after the fork, so jsx-a11y/alt-text becomes jsx-a11y-x/alt-text. @next/eslint-plugin-next is an optional peer dependency, loaded only when config('nextjs') is called, so the other rule sets do not need it.

ESLint React covers most of eslint-plugin-react and eslint-plugin-react-hooks. What is genuinely lost:

| Rule | Replacement | | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | react/jsx-no-duplicate-props | TypeScript reports this as TS17001 | | react/jsx-uses-react, react/jsx-uses-vars, react/jsx-no-undef | redundant — ESLint 10 tracks JSX references natively | | react/no-is-mounted, react/require-render-return | class-component patterns, not relevant to modern React | | react-hooks/config, react-hooks/gating, react-hooks/incompatible-library, react-hooks/preserve-manual-memoization | none — ESLint React does not implement these React Compiler rules | | react/no-unescaped-entities | none |

Upgrading from v9

nextjs no longer loads eslint-config-next. Replace it in your devDependencies:

$ npm uninstall eslint-config-next
$ npm install -D @next/eslint-plugin-next@16

The @next/next rules, their severities and the ignored paths are the same as before. What changes:

  • Accessibility checks are now errors, and there are more of them. react and nextjs switch on eslint-plugin-jsx-a11y-x's recommended preset with a few rules turned off — 20 rules at error and 1 at warn (see Accessibility rules). That includes the six jsx-a11y rules nextjs had as warn in v9, so a Next.js project that carried those warnings now fails its lint run.

  • react gains the rest of what nextjs already had that is not Next.js-specific: import-x/no-anonymous-default-export (warn), and JSX in plain .js files now parses.

  • react/*, react-hooks/* and import/* rule ids are gone from nextjs. They came from the plugins eslint-config-next registered, and v9 switched every one of them off anyway. A consuming config that turns one of them back on now fails with Could not find plugin, and an eslint-disable comment naming one reports Definition for rule … was not found. Use the @eslint-react/* or import-x/* equivalent.

  • Accessibility rules are renamed from jsx-a11y/* to jsx-a11y-x/*, after the fork that provides them. v9's nextjs registered them as jsx-a11y/*, so a config line naming one now fails with Could not find plugin "jsx-a11y", and an eslint-disable comment naming one reports Definition for rule … was not found. Renaming the prefix is all it takes; this finds every mention:

    $ grep -rn 'jsx-a11y/' --exclude-dir=node_modules --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' --include='*.mjs' .
  • settings.react.version is no longer set, since nothing reads it any more.

Upgrading from v8

The plugin namespace for this package's own rules changed from smartive to @smartive-eslint, so smartive/forbid-component-props is now @smartive-eslint/forbid-component-props. Nothing about the rule's behaviour or options changed. The shipped rule sets are updated; what needs changing is every mention of the old id in consuming projects:

$ grep -rn 'smartive/forbid-component-props' --include='*.ts' --include='*.tsx' --include='*.js' --include='*.mjs' .

How each kind of mention fails is worth knowing, because only two of the three are loud:

| Mention | What happens on v9 | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | 'smartive/forbid-component-props': ['warn', …] in a config | ESLint refuses to start: Could not find plugin "smartive" in configuration | | // eslint-disable-next-line smartive/forbid-component-props | Definition for rule 'smartive/forbid-component-props' was not found, and the suppressed warning comes back | | 'smartive/forbid-component-props': 'off' in a config | silently ignored — the rule stays on at its default error |

The third is the one to search for: turning a rule off under a namespace that no longer exists is not an error, so the override simply stops taking effect.

The same release also adds three stylistic JSX rules to the react and nextjs rule sets. They are new errors on code that passed on v8, and all three are auto-fixable.

@smartive-eslint/forbid-component-props is raised from warn to error in the same release. It reports on exactly the code it reported on before, so nothing new is flagged — but a project that was carrying those warnings will now fail its lint run. It is not auto-fixable: each report needs either the prop removed, the component added to allowedFor/allowedForPatterns, or the rule turned down locally.

Upgrading from v7

Expect new errors on code that passed before. ESLint React's recommended-type-checked preset is considerably broader than the eslint-plugin-react set it replaces, so upgrading turns on 44 checks that had no predecessor — 14 as error, 30 as warn. These are new findings in unchanged code, not regressions.

The 14 that fail a build:

| Rule | Catches | | ----------------------------------------------------- | ------------------------------------------------------------- | | @eslint-react/no-leaked-conditional-rendering | {count && <Foo />} rendering 0, or crashing on a non-node | | @eslint-react/no-nested-component-definitions | components declared inside other components | | @eslint-react/no-nested-lazy-component-declarations | lazy() called inside a component | | @eslint-react/jsx-no-key-after-spread | key placed after {...props} | | @eslint-react/jsx-no-namespace | namespaced JSX names | | @eslint-react/jsx-no-children-prop-with-children | children passed both as prop and as JSX children | | @eslint-react/dom-no-void-elements-with-children | children on <img>, <br> and friends | | @eslint-react/dom-no-flush-sync | flushSync, which forces a synchronous re-render | | @eslint-react/dom-no-use-form-state | the removed useFormState | | @eslint-react/no-access-state-in-setstate | reading this.state inside setState | | @eslint-react/rsc-function-definition | invalid server-component function forms | | no-unassigned-vars | declared, never assigned, still read | | no-useless-assignment | a value overwritten before it is read | | preserve-caught-error | rethrowing without passing cause |

The last three are core ESLint rules, new to js.configs.recommended in @eslint/js v10.

The 30 warnings cluster into a few families: effect-cleanup leaks (@eslint-react/web-api-no-leaked-timeout, -interval, -event-listener, -fetch, and the two observer rules), React 19 deprecations (no-forward-ref, no-context-provider, no-use-context, no-clone-element, the no-children-* set), naming conventions (naming-convention-context-name, -id-name, -ref-name) and @eslint-react/no-array-index-key.

Rule ids also changed, so existing suppressions stop working — silently, since an eslint-disable naming an unknown rule is simply inert. Anything mentioning react/*, react-hooks/* or import/* needs rewriting to @eslint-react/*, import-x/* or @smartive-eslint/*.

Accessibility rules

The react and nextjs rule sets use eslint-plugin-jsx-a11y-x's recommended preset, with every rule at error. Its rules are named jsx-a11y-x/…, after the plugin. On top of it, two rules the preset leaves out are switched on:

| Rule | Level | Flags | | ---------------------------------------- | ------- | ------------------------------------------------------- | | jsx-a11y-x/lang | error | an invalid lang on <html>, such as lang="english" | | jsx-a11y-x/no-aria-hidden-on-focusable | warn | aria-hidden on something the keyboard can still focus |

and these are switched off:

| Rule | Why | | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | jsx-a11y-x/anchor-is-valid | <a onClick> and href="#" are common in existing code, and each fix is a restyle | | jsx-a11y-x/no-static-element-interactions | a click-to-close modal backdrop is legitimate | | jsx-a11y-x/click-events-have-key-events | flags the same code as the rule above | | jsx-a11y-x/no-noninteractive-element-interactions | the same problem on <li>, <h2> and friends | | jsx-a11y-x/no-noninteractive-tabindex | scrollable containers need tabIndex={0} for keyboard scrolling | | jsx-a11y-x/media-has-caption | cannot see captions a video player adds | | jsx-a11y-x/label-has-associated-control | only recognises native controls, so <label>Name <TextField /></label> is reported | | jsx-a11y-x/no-autofocus | focusing the first field of a dialog is correct | | jsx-a11y-x/img-redundant-alt | judges wording: alt="Photo booth at the party" is reported for containing "photo" | | jsx-a11y-x/iframe-has-title | iframes are mostly third-party embeds, rare enough to catch in review | | jsx-a11y-x/no-distracting-elements | <marquee> and <blink> do not appear in modern React code | | jsx-a11y-x/mouse-events-have-key-events | also fires when hovering reveals nothing essential, e.g. analytics or prefetching | | jsx-a11y-x/prefer-tag-over-role | suggests from a lookup table, so <svg role="img"> and <div role="presentation"> are told to become <img> |

control-has-associated-label and anchor-ambiguous-text are off in the preset already. In nextjs, alt-text also checks next/image's <Image>.

jsx-a11y-x/no-redundant-roles stays on, but allows role="list" on <ul> and <ol>: Safari drops the list semantics of a list styled list-style: none (Tailwind's list-none, for instance), and role="list" is the standard way to restore them.

Stylistic JSX rules

ESLint Stylistic is registered in the react and nextjs rule sets.

Three rules are enabled:

| Rule | Flags | | ------------------------------------- | ------------------------------------------------------------------------------------ | | @stylistic/jsx-curly-brace-presence | <Card label={'x'} /> and <span>{'x'}</span> — braces around a string literal | | @stylistic/jsx-self-closing-comp | <Card></Card> — a component with no children that does not close itself | | @stylistic/jsx-pascal-case | <Test_component /> — a component name that is neither PascalCase nor a DOM element |

All three are error and all three are auto-fixable, so eslint --fix clears them in one pass.

jsx-curly-brace-presence is configured with an object and propElementValues: 'always', which is what its documentation recommends — the brace-less prop=<Icon /> form the 'never' setting produces is "obscure, and intentionally undocumented". It would also fight Prettier, which puts the braces straight back, and ESLint reports the pair as a circular fix.

Custom rules

@smartive-eslint/forbid-component-props

Forbids the given props on components (<Foo />, <Foo.Bar />) while leaving intrinsic elements (<div />) alone. It replaces react/forbid-component-props, which has no equivalent in ESLint React. Enabled in the react and nextjs rule sets as:

'@smartive-eslint/forbid-component-props': ['error', { forbid: ['style', 'className'] }]

Each entry in forbid is either a prop name or an object that narrows where the prop stays allowed:

| Key | Meaning | | -------------------- | ---------------------------------------------------------------------------------------- | | propName | The forbidden prop (required). | | allowedFor | Component names the prop is still allowed on, matched exactly. | | allowedForPatterns | Globs (* for any run of characters, ? for one) the component name may match instead. | | message | Replaces the default report message. |

Component names are matched on their full JSX name, so <Mantine.Button /> matches Mantine.*.

'@smartive-eslint/forbid-component-props': [
  'error',
  {
    forbid: [
      {
        propName: 'className',
        allowedFor: ['NextImage', 'NextLink'],
        allowedForPatterns: ['*Icon', 'Mantine*'],
        message: 'Avoid using className except NextImage, NextLink, icons and Mantine components',
      },
    ],
  },
]

Development

$ npm run check-types  # type-check the config sources
$ npm run prettier     # formatting
$ npm test             # build, type-check the tests, then run them

The tests in test/ lint the fixtures in test/fixtures/ with each of the three rule sets and assert that a given fixture line is flagged. They deliberately never assert on rule ids, so that swapping out a plugin for an equivalent one does not require rewriting them.

npm test runs the TypeScript test files directly through Node's type stripping, which needs Node 22.18 or newer.