Skip to content

Adding Intellisense To Attribute Styles

Published: at 05:41 AM

This only works for HTML purists and TSX (sorry for non-TypeScript-ers) – although your IDE may apply TS intellisense if you are using JS 🤷 (inn’it VSCode?).

What I can say: after discovering this possibility, I am super keen on refactoring my CSS utilities and some components with variants to give it a try.

The only pushback I have for now is performance concerns. To me it’s ok to use array.map(…).filter(…) instead of array.reduce(…) for readability because the performance loss is acceptable, that I don’t know about attribute selectors.

I’ve read that exact attribute selectors [attr="value"] are approximately as good as classes. My guess is that [attr^=] (starts with) and [attr$=""] (ends with) are fairly good as well. Now what about [attr~=] and [attr*=]? Maybe they are a bit less performant compared to others. If anyone has an answer I’m super curious to hear it.

Table of contents

Open Table of contents

CSS sample

<div is-rounded />
<div is-rounded="thin" />
<div is-rounded="block-end" />
<div is-rounded="thick block-end" />
<style>
  /* utility.css */
  [is-rounded] {}
  [is-rounded^="thin"] {}
  [is-rounded^="thick"] {}
  [is-rounded$="block-end"] {}
</style>

The associated TypeScript type

type RoundedSize = "thin" | "thick" | …
type RoundedPosition = "block-end" | "inline" | …
export type Rounded =
  | true // apply default rounded styles
  | RoundedSize // change size but not position
  | RoundedPosition // change position but not size
  | `${RoundedSize} ${RoundedPosition}` // must specify size *and then* position

TSX – React, Solid, …

I haven’t checked all the tools of course, there’s just too many of them using TSX.

If it doesn’t work with your tool, follow this methodology
  1. In any component file, type a known attribute. I usually spot a global one like class.
  2. Follow the type definition (usually alt+click).
  3. Spot the attributes interface that is also used in the global namespace (usually named JSX).
  4. Augment that namespace and that attributes interface.
// utility.d.ts

// That way if the file is imported in the code, everything gets intellisense !
declare module "utility.css" {
  declare global {
    namespace JSX {
      interface IntrinsicAttributes {
        "is-rounded"?: Rounded;
      }
    }
  }
}
// in your entry point, mine is src/main.tsx
import "utility.css";

For Svelte

// in your entry point, mine is src/main.ts
const component = new AppComponent({
  target: document.body,
  props: { … }
})

// …

declare global {
  namespace svelteHTML {
    interface HTMLAttributes {
      'is-rounded'?: Rounded
    }
  }
}

// you can externalize this into a another file. I would suggest you do.

VSCode HTML language features

I haven’t checked that one yet, just I read the doc. Here’s my perplexity.ai search about it, and here’s what it says:

You can declare a custom-attributes.html-data.json file.

You can create a VS Code extension that contributes custom HTML data by defining the contributes.html.customData property in the extension’s package.json file. This property should point to the JSON files containing the custom data definitions.

{
  "contributes": {
    "html": {
      "customData": ["./custom-attributes.html-data.json"]
    }
  }
}

Now let’s populate the custom-attributes.html-data.json file:

{
  "version": 1.1,
  "globalAttributes": [
    {
      "name": "rounded",
      "description": "Apply rounding with options to an element. Example: <div rounded /> <div rounded='{size}' /> <div rounded='{position}' /> or <div rounded='{size} {position}' ",
      "values": [
        {
          "name": "",
          "description": "apply default rounding"
        },
        {
          "name": "/^(thin|thick)$/",
          "description": "apply sized rounding"
        },
        {
          "name": "/^(block-end)$/",
          "description": "apply positioned rounding"
        },
        {
          "name": "/^(thin|thick) (block-end)$/",
          "description": "apply sized and positioned rounding"
        }
      ]
    }
  ]
}