Skip to content

2.4

ESLint Plugin ​

An ESLint plugin that enforces Pixel 3 design system usage patterns through ESLint rules, ensuring consistency across codebases and teams. It detects incorrect or discouraged design system implementation early during development and promotes maintainable, predictable code through shared standards and best practices.

Installation ​

bash
pnpm add -D @mekari/pixel3-eslint-plugin

Configuration ​

Vite ​

ts
// eslint.config.ts
import type { Linter } from 'eslint'
import pixelPlugin from '@mekari/pixel3-eslint-plugin'

export default [
  {
    plugins: {
      pixel: pixelPlugin
    },
    rules: {
      'pixel/no-hex-color': 'error',
      'pixel/no-raw-html-element': 'error',
      'pixel/no-style-boundary-violation': 'error',
      'pixel/valid-color-token': 'error'
    }
  }
] satisfies Linter.Config[]

Nuxt ​

If you're using the @nuxt/eslint module, extend the generated config with withNuxt:

js
// eslint.config.mjs
import withNuxt from './.nuxt/eslint.config.mjs'
import pixelPlugin from '@mekari/pixel3-eslint-plugin'

export default withNuxt({
  plugins: {
    pixel: pixelPlugin
  },
  rules: {
    'pixel/no-hex-color': 'error',
    'pixel/no-raw-html-element': 'error',
    'pixel/no-style-boundary-violation': 'error',
    'pixel/valid-color-token': 'error'
  }
})

Rules ​

no-raw-html-element ​

Rule purpose

no-raw-html-element prevents direct usage of native HTML elements such as div, span, button or input when Pixel 3 already provides an equivalent component. For layout containers, do not use raw div, use Pixel.div instead so spacing, styling tokens, accessibility patterns and design system conventions stay consistent.

When this rule triggers

  • Using a raw HTML element for UI structure or layout when a Pixel component exists.
  • Using <div> as a container instead of <Pixel.div>.
  • Mixing native HTML primitives with Pixel 3 components in a way that bypasses design system standards.

Incorrect

vue
<template>
  <div class="background-surface">
    <span class="text-secondary">Customer information</span>
  </div>
</template>

Correct

vue
<template>
  <Pixel.div bg="background.surface">
    <Pixel.span color="text.secondary">Customer information</Pixel.span>
  </Pixel.div>
</template>

no-hex-color ​

Rule purpose

no-hex-color prevents direct usage of hardcoded hex color values such as #FFFFFF, #172B4D or #FF5630. Use Pixel 3 design tokens instead so colors remain consistent, theme-aware and easier to maintain across products.

When this rule triggers

  • Using a raw hex color value in Vue template attributes, inline styles or component props.
  • Using hardcoded colors in style bindings instead of Pixel 3 color tokens.
  • Defining custom colors that bypass approved design system tokens.

Incorrect

vue
<template>
  <Pixel.div bg="#FFFFFF" color="#172B4D"> Customer information </Pixel.div>
</template>

Correct

vue
<template>
  <Pixel.div bg="background.surface" color="text.secondary"> Customer information </Pixel.div>
</template>

Options

  • allow (string[], default: []): hex color values to permit even though they'd otherwise be flagged, matched case-insensitively.

no-style-boundary-violation ​

Rule purpose

no-style-boundary-violation enforces the styling boundary between Pixel.* elements and Mp* components. Pixel.* elements, plus the layout exceptions MpFlex, MpScrollbar and MpSkeleton, expose style props directly and must be styled through those props. Every other Mp* component does not expose style props and must be styled through the css() function instead.

When this rule triggers

  • Using the style/:style attribute on a Pixel.* element instead of style props (e.g. display, mt, bg).
  • Using :class="css(...)" on a Pixel.* element for styling that style props already support.
  • Using the style/:style attribute on an Mp* component (other than MpFlex, MpScrollbar, MpSkeleton) instead of the css() function.

Incorrect

vue
<template>
  <Pixel.div :class="css({ bg: 'background.surface', mt: '4' })">
    <MpText style="color: #172B4D;">Customer information</MpText>
  </Pixel.div>
</template>

Correct

vue
<template>
  <Pixel.div bg="background.surface" mt="4">
    <MpText :class="css({ color: 'text.secondary' })">Customer information</MpText>
  </Pixel.div>
</template>

valid-color-token ​

Rule purpose

valid-color-token validates color-related prop/style values against the real Pixel 3 design-token set. It catches two things: typos and non-existent token paths (e.g. background.neutral.sutble, gray.999) that would otherwise silently pass, since component prop types intentionally widen to accept any string so autocomplete keeps working, so TypeScript can't catch these mistakes at compile time and real raw/reference tokens (e.g. gray.100, blue.500) used where semantic tokens are required, when targeting design-token v2.4 (dark-mode support), raw tokens don't adapt to theme/dark mode.

When this rule triggers

  • A color-related prop/style-prop (color, bg, background, borderColor, fill, stroke or any key ending in Color) is assigned a string that isn't a hex color.
  • tokenVersion: '2.4' (the default) and the value is a real raw color token (<family>.<shade>, e.g. gray.100) instead of a semantic one.
  • Applies to static Vue attributes, :prop="..." bindings (including ternary/logical fallbacks) and css({ ... }) object properties.

Incorrect

vue
<template>
  <Pixel.div bg="background.neutral.sutble">
    <MpText :class="css({ color: 'gray.400' })">Customer information</MpText>
  </Pixel.div>
</template>

Correct

vue
<template>
  <Pixel.div bg="background.neutral.subtle">
    <MpText :class="css({ color: 'text.secondary' })">Customer information</MpText>
  </Pixel.div>
</template>

Options

  • allow (string[], default: []): extra color values to permit beyond the generated token list, e.g. a custom token that's still being migrated.
  • tokenVersion ('2.1' | '2.4', default: '2.4'): the design-token version the project targets. By default, the rule requires semantic tokens for real color values. Set to '2.1' only for projects that still target token v2.1 and need to keep allowing raw tokens.

WARNING

This rule reads the real token list from @mekari/pixel3-styled-system, resolved from the linted project. If that package can't be found, the rule silently does nothing rather than failing the lint run.

SEVERITY DURING MIGRATION

Dual-version fallbacks like isNextTheme ? 'text.secondary' : 'gray.400' are flagged on purpose, as a burndown marker for v2.4 migration. Use 'warn' instead of 'error' while migrating, then switch back once it's done.