pub-registry

style_lint

v1.0.0

Lint rules and class sorter for the Style's class strings.

tailwindstylinglinter
SDKDartFlutter
Platformandroidioslinuxmacoswebwindows

style_lint

Analyzer plugin for the style package. Reads the Tailwind class strings you pass to Style(...) and reports typo'd classes/variants and unsorted utility strings directly in your IDE.

Installation

style_lint is an analyzer plugin — it's declared only in the plugins: section of your analysis_options.yaml (which specifies its source and version).

plugins:
  style_lint:
    hosted: https://pub.mariuti.com
    version: ^1.0.0

Restart the Dart Analysis Server (or your IDE) after any change to the plugins: section — plugin isolates are only loaded on startup.

If your project is a pub workspace, the plugins: block can only live at the workspace root (a plugins: block in a member package's own analysis_options.yaml is invalid — the analyzer emits a plugins_in_inner_options warning and ignores it). A member package that has its own analysis_options.yaml shadows the root, so the plugin won't run on its files unless that file includes the root:

include:
  - ../../analysis_options.yaml
  - package:flutter_lints/flutter.yaml

Members with no analysis_options.yaml of their own inherit the plugin automatically.

Rules

Rule Default What it catches
unknown_class On (warning) Style('bg-blu-500') — typo'd class.
unknown_variant On (warning) Style('hove:bg-blue-500') — typo'd variant.
duplicate_class On (warning) Style('p-4 p-4') — a token repeated verbatim.
conflicting_classes On (warning) Style('bg-red-500 bg-blue-500') — later class silently wins (StyleSpec merges last-wins).
unsorted_classes On (info) Style('text-white p-4') — not in canonical Tailwind order.

duplicate_class and conflicting_classes each ship an IDE quick-fix that removes the offending token — "Style: Remove duplicate class" always, and "Style: Remove conflicting class" only when the overridden class is fully covered by the winner (so removal can't change anything the winner doesn't already set).

All five rules are on by default. Turn any of them off (or lower its severity) per-project via diagnostics::

plugins:
  style_lint:
    hosted: https://pub.mariuti.com
    version: ^1.0.0
    diagnostics:
      unsorted_classes: false   # e.g. if you don't want the sort nag

Suppressing diagnostics

Suppression requires the qualified form — a bare rule name is silently inert for plugin diagnostics:

// ignore: style_lint/unknown_class
Style('bg-blu-500', child: child);

Custom tokens (style_lint: in analysis_options.yaml)

Custom colors, breakpoints, and variants registered on a StyleThemeData/StyleVariants aren't visible to the analyzer. Declare them in a top-level style_lint: section of the analysis_options.yaml next to your pubspec.yaml:

style_lint:
  palettes:
    - brand
  breakpoints:
    - tablet
  custom_properties:
    - --brand-color
  variants:
    - compact

Also supports spacing, typography, letter_spacing, leading, radius, shadows, and max_widths.

Wrap with Style

Put the cursor on any Flutter Widget expression and invoke one of the wrap assists (the lightbulb / ⌘. / Ctrl+. quick-fix menu):

Text('Hello')
// "Wrap with Style" -> caret left inside the empty '' ready for classes:
Style('', child: Text('Hello'))
// "Wrap with Style(children:)" -> the flex/grid shape:
Style('', children: [Text('Hello')])

The package:style import is added automatically when the file doesn't already have it.

With the cursor inside an existing Style(...) call, two more assists switch between the two shapes:

  • "Convert to Style(children:)" — turns child: <widget> into children: [<widget>].
  • "Convert to Style(child:)" — turns a single-element children: [<widget>] back into child: <widget> (offered only for a one-element list, so it never drops widgets).

Sort classes

dart run style_lint:sort_classes              # rewrite lib/ in place
dart run style_lint:sort_classes --check lib   # CI: report only, exit 1 if unsorted

An on-demand "Style: Sort classes" IDE assist is also available with the cursor inside any Style(...) classes string. Sorting reproduces Tailwind v4's own class order exactly (the same order the prettier-plugin-tailwindcss produces).

Because it matches Tailwind, sorting does reorder conflicting utilities (e.g. px-2 p-4, bg-red-500 bg-blue-500). Style(...) merges last-class-wins, so that can change the rendered result — sorting is a deliberate, user-invoked action, and conflicting_classes flags such strings so you can resolve them first.

Caveats

  • IDE only — dart analyze/flutter analyze don't run plugin isolates, so they won't report style_lint diagnostics; use sort_classes --check in CI.
  • Plugin-provided fixes aren't dart fix --apply-appliable — use the sort_classes CLI for bulk sorting.
  • No format-on-save equivalent — sorting only happens via the CLI or the assist/fix.
  • Bracket contents ([...]) aren't validated — only the utility root is checked.