Style Pastel


Inline styles read flat — every property looks the same. Style Pastel tints each declaration by category so they fall into visual groups at a glance:

- Layout (blue) —
display, align-items, gap, …
- Box (emerald) —
padding, margin, width, …
- Surface (pink) —
background, border-radius, box-shadow, …
- Typography (amber) —
font-size, color, line-height, …
- Motion (violet) —
transition, transform, …
- Other (gray) —
cursor, user-select, pointer-events, …
Works in both style="..." strings and JSX style={{ ... }} objects (kebab-case and camelCase classify the same way).
Features
- Category-based coloring — every declaration's property name is colored by category
- CSS variable highlighting — both
--brand: red; declarations and var(--brand) references inside values get a distinct cool tone (slate-300)
- Multi-attribute support — picks up
style, :style (Vue), [style] (Angular), ngStyle, and JSX style={ ` ... ` } template literals
- Long property aware —
padding-inline-start, border-top-left-radius, -webkit-mask-image, etc. classify by their longest matching prefix
- Debounced updates — re-highlights 150ms after edits to stay snappy on large files
- Viewport rendering — creates decorations for visible lines and a 20-line margin; split editors share document analysis
Categories
Six high-level groups, sharing the same palette as Tailwind Pastel so the visual language stays consistent if you use both:
| Category |
Color |
Covers |
| Layout |
Blue |
display, position, flex/grid, gap, justify/align/place-*, overflow |
| Box |
Emerald |
sizing (width, height, min/max-*) and spacing (padding-*, margin-*) |
| Typography |
Amber |
font-*, color, text-*, line-height, letter-spacing, white-space |
| Surface |
Pink |
background-*, border-*, outline-*, box-shadow, opacity, filter, mask-* |
| Motion |
Violet |
transition-*, animation-*, transform, translate, rotate, scale |
| Other |
Gray |
cursor, user-select, pointer-events, scroll-*, touch-action, fallback |
CSS custom properties (--brand) and var(--brand) references use a separate slate tone so they stand out from regular property names.
Supported Languages
- TypeScript React (
.tsx)
- JavaScript React (
.jsx)
- HTML
- Vue
- Svelte
- Astro
Detection
Style strings are extracted from the following attribute forms:
style="..." / style='...' (HTML, Svelte, Astro, JSX)
style={ ` ... ` } (JSX tagged-template inside expression — no ${} interpolation)
style={{ ... }} (JSX object form — camelCase keys, kebab-case quoted keys, vendor prefixes like WebkitMaskImage, and '--brand' custom properties all classify correctly)
:style="..." (Vue)
[style]="..." (Angular property binding)
ngStyle="..." (Angular)
For string-based attributes, each prop: value; pair becomes one token. Parentheses and brackets in values are respected, so commas/semicolons inside rgb(0, 0, 0) or calc(100% - 16px) don't split a declaration.
For JSX object form, each key: value pair becomes one token, separated at top-level ,. String literals, template literals (including ${} interpolation), comments, and nested ()/[]/{} are all skipped when looking for the separator. Spread (...base) and computed keys ([expr]) are ignored.
Configuration
| Setting |
Type |
Default |
Description |
stylePastel.enabled |
boolean |
true |
Enable category highlighting |
Commands
| Command |
Description |
Style Pastel: Toggle Highlighting |
Flip stylePastel.enabled — writes to workspace settings if defined there, otherwise to global. |
Starting with 0.1.0, only visible documents retain parsed declarations. Hiding or closing a document, or disabling highlighting, releases its cache and pending timers. The cache stores tokens without a separate copy of the full source or a line-offset table. Scrolling within the painted margin reuses existing decorations.
Small edits within one plain declaration value (such as padding: 16px or JSX paddingTop: 16) update cached tokens directly. A bounded burst of these edits shifts subsequent tokens once. Property names, quotes, separators, expressions, edits across declarations, and larger batches trigger a full parse so multiline style strings and JSX objects retain their context.
- Documents above 2,097,152 UTF-16 code units or 200,000 declarations are skipped. Highlighting resumes when an edit brings them back within the limits.
- Each editor applies at most 4,000 decoration ranges, including CSS variable references. Visible property names and references take priority over the margin, even within multiline values. Dense views may be only partially highlighted; scrolling retries the visible range.
- Pending incremental edits are limited to 32 events and 2,048 inserted/deleted code units. Larger edits retain only a refresh timer until the 150ms debounce expires.
Development
npm run typecheck
npm test
npm run build
npm run benchmark
npm run benchmark -- --baseline <git-ref>
In an Extension Development Host (F5), hovering over a declaration also shows its property name, category, and source text. This inspection hover is enabled only in development mode.
Tests cover viewport rendering, split editors, cache disposal, size limits, parser equivalence while editing, and the existing samples. Sample compatibility is checked against token counts and digests captured from the pre-optimization commit 8aa1d9e.
The benchmark compares decoration allocations, editing time, and approximate retained JavaScript heap with a mocked VS Code API. It uses a fresh process and post-GC heap delta for each case; mock document storage, real debounce delay, VS Code IPC, and rendering are excluded. Use an Extension Development Host to check actual editor behavior and total memory use.
Example comparison of 0.1.0 with 8aa1d9e on Node 24.19.0 (10,000 rows, 80,000 declarations, 40 visible lines; reproduce with npm run benchmark -- --baseline 8aa1d9e):
| Measurement |
Before |
After |
| Initial decoration ranges |
90,000 |
540 |
| Approximate retained heap |
20.4 MiB |
9.5 MiB |
| Equal-length value edit, median |
24.9 ms |
0.3 ms |
| Property-name edit, median |
19.8 ms |
29.4 ms |
Property-name edits now perform a full parse to preserve multiline context, so that case can take longer. Timings and heap deltas vary by environment; these are mock measurements, not total VS Code memory savings.
License
MIT — see LICENSE.md.
| |