DEV Community

Cover image for Extending Emmet and VS Code — and discovering 415 CSS properties
Mads Stoumann
Mads Stoumann

Posted on

Extending Emmet and VS Code — and discovering 415 CSS properties

I use Emmet everyday. You might too, without even knowing — it's built-in to VS Code!
When you type bdrs, Emmet magically transforms that to border-radius. Etcetera.

It saves you a lot of typing.

But that’s not the only thing, I use Emmet for. I like to name my custom properties with component-name + emmet-abbrevaiation, so the property for border-radius for a component called “hero”, will be --hero-bdrs. It keeps the custom property-names short and concise.

Unforunately, Emmet isn't updated regularly — for instance, none of the logical properties that are now available in all browsers, are available in Emmet.

In fact, there are almost 200 properties missing. Luckily, we can easily extend Emmet.


Data

First, we need some data. Grab Emmet's css.json, and MDN's properties.json.
Place these files locally. We'll use a Promise.all to grab the array of files (we might need more later, so this is a safe way to do it):

Promise.all(
  urls.map((url, index) => fetch(url)
    .then(r => r.json())
    .then(json => {
      const key = urls[index].split('.')[0];
      data[key] = json;
    })
    .catch(error => ({ error, url }))
  )
).then(() => {
  // Stuff here ...
})
Enter fullscreen mode Exit fullscreen mode

Now, we have access to the data as data.emmet and data.properties.
The data in data.properties is our "master data", as this is a list of all CSS properties.
For the Emmet-data, we need to filter out all the "extra stuff" that Emmet provides, and only treat the data which matches a CSS property directly. In other words: we need to filter the data and remove old, rendundant stuff like border-bottom-image and overflow-style:

const emmetMap = new Map();
for (const [key, value] of Object.entries(data.emmet)) {
  const [subkey, subvalue] = value.split(':')
  if (data.properties.hasOwnProperty(subkey)) {
    if (!emmetMap.has(subkey)) emmetMap.set(subkey, key);

  }
  else {
    delete data.emmet[key];
  }
}
Enter fullscreen mode Exit fullscreen mode

Next, we iterate all CSS properties, and check, if it has a matching Emmet-entry. If not, we'll create our own Emmet-abbreviation based on the property-name.

For that, we split the key by -, so padding-inline-end becomes:
['padding', 'inline', 'end']

If the array has a length greater than 0, we'll grab the first letter of each entry, so we'll end up with pie. Yummy, that's a good abbreviation for padding-inline-end!

If the array does not have a length, we'll use the 3 first chars instead:
key.slice(0, 3)

Before we use the new key, we'll have to check if it exists already:

const values = Array.from(emmetMap.values());
if (values.includes(emmetKey)) { ... }
Enter fullscreen mode Exit fullscreen mode

If the key does exist already, we'll output it to the console.
So ... we get 14 keys that exist already:

  • ac accent-color
  • bdb box-decoration-break
  • bd box-direction
  • cp clip-path
  • fs font-smooth
  • fs font-synthesis
  • mb margin-block
  • mt margin-trim
  • mb mask-border
  • mr mask-repeat
  • mt mask-type
  • ml max-lines
  • pb padding-block
  • ta touch-action

We could write some clever code to generate an alternative Emmet-key, but for such small amount, let's just change them manually, and add them to emmet.json:

"acc": "accent-color",
"bodb": "box-decoration-break",
"bxd": "box-direction",
"clp": "clip-path",
"fsmo": "font-smooth",
"fsy": "font-synthesis",
"mab": "margin-block",
"mat": "margin-trim",
"msb": "mask-border",
"msr": "mask-repeat",
"mty": "mask-type",
"mal": "max-lines",
"pab": "padding-block",
"toa": "touch-action"
Enter fullscreen mode Exit fullscreen mode

Let's run the code again, making sure there are no unknown keys.
Finally, if it's a new Emmet-key, we'll update data.emmet with the new entry:

data.emmet[emmetKey] = key

And in data.properties, we add a new emmet-entry per property:

data.properties[key].emmet = emmetKey


Let's log the data, and see what we've accomplished:

console.log(data.properties)
console.log(data.emmet)
Enter fullscreen mode Exit fullscreen mode

Now, just right-click on the object in Dev Tools, and chose "Copy object". You can also use a console-script to accomplish this. Paste it in your favourite editor (probably VS Code!) and save it.


Extending VS Code

… And speaking of VS Code. Let’s look into how we can extend the Emmet-implementation, so it can use all the new abbreviations, we've created.

Rename the file to snippets.json and add some wrapper objects around the list of properties:

{
  "css": {
    "snippets": {
      "at": "animation-timeline",
      "all": "all",
      "ar": "aspect-ratio",
... etc ...
Enter fullscreen mode Exit fullscreen mode

I had to add some entries to settings.json in VS Code, in order for it to recognize the new Emmet-snippets:

"emmet.triggerExpansionOnTab": true,
"files.associations": {"*css": "css"},
"emmet.useInlineCompletions": true,
"emmet.extensionsPath": [
  "path-to-snippets.json"
]
Enter fullscreen mode Exit fullscreen mode

Now, type pie and hit Tab:

The new Emmet-snippet in action

Repo

I’ve added all the code and the new snippets.json in this repo:

https://github.com/madsstoumann/emmet-vscode

The greatest surprise of this project, was learning there are 415 CSS Properties!


Complete Emmet CSS List

And here's the complete, updated list of Emmet abbreviations for CSS properties:

Emmet Property
acc accent-color
ac align-content
ai align-items
as align-self
at align-tracks
all all
anim animation
animdel animation-delay
animdir animation-direction
animdur animation-duration
animfm animation-fill-mode
animic animation-iteration-count
animn animation-name
animps animation-play-state
animtf animation-timing-function
at animation-timeline
ap appearance
ar aspect-ratio
azi azimuth
bf backdrop-filter
bfv backface-visibility
bg background
bga background-attachment
bbm background-blend-mode
bgcp background-clip
bgc background-color
bgi background-image
bgo background-origin
bgp background-position
bgpx background-position-x
bgpy background-position-y
bgr background-repeat
bgsz background-size
bo block-overflow
bs block-size
bd border
bb border-block
bbc border-block-color
bbs border-block-style
bbw border-block-width
bbe border-block-end
bbec border-block-end-color
bbes border-block-end-style
bbew border-block-end-width
bbs border-block-start
bbsc border-block-start-color
bbss border-block-start-style
bbsw border-block-start-width
bdb border-bottom
bdbc border-bottom-color
bdblrs border-bottom-left-radius
bdbrrs border-bottom-right-radius
bdbs border-bottom-style
bdbw border-bottom-width
bdcl border-collapse
bdc border-color
beer border-end-end-radius
besr border-end-start-radius
bdi border-image
bio border-image-outset
bir border-image-repeat
bis border-image-slice
bis border-image-source
biw border-image-width
bi border-inline
bie border-inline-end
bic border-inline-color
bis border-inline-style
biw border-inline-width
biec border-inline-end-color
bies border-inline-end-style
biew border-inline-end-width
bis border-inline-start
bisc border-inline-start-color
biss border-inline-start-style
bisw border-inline-start-width
bdl border-left
bdlc border-left-color
bdls border-left-style
bdlw border-left-width
bdrs border-radius
bdr border-right
bdrc border-right-color
bdrst border-right-style
bdrw border-right-width
bdsp border-spacing
bser border-start-end-radius
bssr border-start-start-radius
bds border-style
bdt border-top
bdtc border-top-color
bdtlrs border-top-left-radius
bdtrrs border-top-right-radius
bdts border-top-style
bdtw border-top-width
bdw border-width
b bottom
ba box-align
bodb box-decoration-break
bxd box-direction
bf box-flex
bfg box-flex-group
bl box-lines
bog box-ordinal-group
bo box-orient
bp box-pack
bxsh box-shadow
bxsz box-sizing
ba break-after
bb break-before
bi break-inside
cps caption-side
cc caret-color
cl clear
cp clip
clp clip-path
c color
pca print-color-adjust
cs color-scheme
colmc column-count
colmf column-fill
colmg column-gap
colmr column-rule
colmrc column-rule-color
colmrs column-rule-style
colmrw column-rule-width
colms column-span
colmw column-width
colm columns
con contain
cnt content
cv content-visibility
coi counter-increment
cor counter-reset
cs counter-set
cur cursor
dir direction
d display
ec empty-cells
fil filter
fx flex
fxb flex-basis
fxd flex-direction
fxf flex-flow
fxg flex-grow
fxsh flex-shrink
fxw flex-wrap
fl float
f font
ff font-family
ffs font-feature-settings
fk font-kerning
flo font-language-override
fos font-optical-sizing
fvs font-variation-settings
fsz font-size
fsza font-size-adjust
fsmo font-smooth
fst font-stretch
fs font-style
fsy font-synthesis
fv font-variant
fva font-variant-alternates
fvc font-variant-caps
fvea font-variant-east-asian
fvl font-variant-ligatures
fvn font-variant-numeric
fvp font-variant-position
fw font-weight
fca forced-color-adjust
gap gap
gd grid
ga grid-area
gac grid-auto-columns
gaf grid-auto-flow
gar grid-auto-rows
gc grid-column
gce grid-column-end
gcg grid-column-gap
gcs grid-column-start
gg grid-gap
gr grid-row
gre grid-row-end
grg grid-row-gap
grs grid-row-start
gt grid-template
gta grid-template-areas
gtc grid-template-columns
gtr grid-template-rows
hp hanging-punctuation
h height
hc hyphenate-character
hyp hyphens
io image-orientation
ir image-rendering
ir image-resolution
im ime-mode
il initial-letter
ila initial-letter-align
is inline-size
is input-security
ins inset
ib inset-block
ibe inset-block-end
ibs inset-block-start
ii inset-inline
iie inset-inline-end
iis inset-inline-start
iso isolation
jc justify-content
ji justify-items
js justify-self
jt justify-tracks
l left
lts letter-spacing
lb line-break
lc line-clamp
lh line-height
lhs line-height-step
lis list-style
lisi list-style-image
lisp list-style-position
list list-style-type
m margin
mab margin-block
mbe margin-block-end
mbs margin-block-start
mb margin-bottom
mi margin-inline
mie margin-inline-end
mis margin-inline-start
ml margin-left
mr margin-right
mt margin-top
mat margin-trim
mas mask
msb mask-border
mbm mask-border-mode
mbo mask-border-outset
mbr mask-border-repeat
mbs mask-border-slice
mbs mask-border-source
mbw mask-border-width
mc mask-clip
mc mask-composite
mi mask-image
mm mask-mode
mo mask-origin
mp mask-position
msr mask-repeat
ms mask-size
mty mask-type
maf masonry-auto-flow
ms math-style
mbs max-block-size
mah max-height
mis max-inline-size
mal max-lines
maw max-width
mbs min-block-size
mih min-height
mis min-inline-size
miw min-width
mbm mix-blend-mode
of object-fit
op object-position
off offset
oa offset-anchor
od offset-distance
op offset-path
op offset-position
or offset-rotate
op opa
ord order
orp orphans
ol outline
olc outline-color
olo outline-offset
ols outline-style
ow outline-width
ov overflow
oa overflow-anchor
ob overflow-block
ocb overflow-clip-box
ocm overflow-clip-margin
oi overflow-inline
ow overflow-wrap
ovx overflow-x
ovy overflow-y
ob overscroll-behavior
obb overscroll-behavior-block
obi overscroll-behavior-inline
obx overscroll-behavior-x
oby overscroll-behavior-y
p padding
pab padding-block
pbe padding-block-end
pbs padding-block-start
pb padding-bottom
pi padding-inline
pie padding-inline-end
pis padding-inline-start
pl padding-left
pr padding-right
pt padding-top
pgba page-break-after
pgbb page-break-before
pgbi page-break-inside
po paint-order
per perspective
po perspective-origin
pc place-content
pi place-items
ps place-self
pe pointer-events
pos position
q quotes
rsz resize
r right
rot rotate
rg row-gap
ra ruby-align
rm ruby-merge
rp ruby-position
sca scale
sc scrollbar-color
sg scrollbar-gutter
sw scrollbar-width
sb scroll-behavior
sm scroll-margin
smb scroll-margin-block
smbs scroll-margin-block-start
smbe scroll-margin-block-end
smb scroll-margin-bottom
smi scroll-margin-inline
smis scroll-margin-inline-start
smie scroll-margin-inline-end
sml scroll-margin-left
smr scroll-margin-right
smt scroll-margin-top
sp scroll-padding
spb scroll-padding-block
spbs scroll-padding-block-start
spbe scroll-padding-block-end
spb scroll-padding-bottom
spi scroll-padding-inline
spis scroll-padding-inline-start
spie scroll-padding-inline-end
spl scroll-padding-left
spr scroll-padding-right
spt scroll-padding-top
ssa scroll-snap-align
ssc scroll-snap-coordinate
ssd scroll-snap-destination
sspx scroll-snap-points-x
sspy scroll-snap-points-y
sss scroll-snap-stop
sst scroll-snap-type
sstx scroll-snap-type-x
ssty scroll-snap-type-y
sit shape-image-threshold
sm shape-margin
so shape-outside
ts tab-size
tbl table-layout
ta text-align
tal text-align-last
tcu text-combine-upright
td text-decoration
tdc text-decoration-color
tdl text-decoration-line
tds text-decoration-skip
tdsi text-decoration-skip-ink
tds text-decoration-style
tdt text-decoration-thickness
te text-emphasis
tec text-emphasis-color
tep text-emphasis-position
tes text-emphasis-style
ti text-indent
tj text-justify
to text-orientation
tov text-overflow
tr text-rendering
tsh text-shadow
tsa text-size-adjust
tt text-transform
tuo text-underline-offset
tup text-underline-position
t top
toa touch-action
trf transform
tb transform-box
trfo transform-origin
trfs transform-style
trs transition
trsde transition-delay
trsdu transition-duration
trsp transition-property
trstf transition-timing-function
tra translate
ub unicode-bidi
us user-select
va vertical-align
v visibility
whs white-space
wid widows
w width
wc will-change
wob word-break
wos word-spacing
wow word-wrap
wm writing-mode
z z-index
zom zoom

Top comments (0)