Repository: tailwindlabs/tailwindcss
Pull request #5568 (2021-09-22 09:43:10)

Improve arbitrary value support
Edit: This PR is fairly big and contains multiple scopes, so I will be splitting this PR into multiple PR's!

PR 1: #5585
PR 2: #5587
PR 3: #5590
PR 4: #5588 

---

This PR will improve arbitrary value support for various plugins. I had to introduce a few more typehints, the names can still be changed if we want to!

Here are the changes to various plugins:

### Background images

Added an `url` typehint, that checks for the `url` prefix.

**Input:**
```html
<div class="bg-[#0088cc]"></div>
<div class="bg-[url('/path-to-image.png')]"></div>
<div class="bg-[url:var(--maybe-a-url-at-runtime)]"></div>
```

**Output:**
```css
.bg-\[\#0088cc\] {
    --tw-bg-opacity: 1;
    background-color: rgb(0 136 204 / var(--tw-bg-opacity))
}
.bg-\[url\(\'\/path-to-image\.png\'\)\] {
    background-image: url('/path-to-image.png')
}
.bg-\[url\:var\(--maybe-a-url-at-runtime\)\] {
    background-image: var(--maybe-a-url-at-runtime)
}
```

---

### Background size & background position

Both `background-size` and `background-position` can accept `length` values like `200px 100px`. This means that this is ambiguous, for this reason I introduced a `size` and `position` typehint.

**Input:**
```html
<div class="bg-[size:200px_100px]"></div>
<div class="bg-[position:200px_100px]"></div>
```

**Output:**
```css
.bg-\[size\:200px_100px\] {
    background-size: 200px 100px
}
.bg-\[position\:200px_100px\] {
    background-position: 200px 100px
}
```

### Font family & font weight

Font families and font weights _can_ be ambiguous but they aren't always. For example, `font-[300]` is a font-weight because you can't have a `font-family` of value `300`. However `font-[black]` can both refer to `font-family: black;` and `font-weight: black;`

For this reason I introduced `family` and `weight` typehints.

**Input:**
```html
<div class="font-[Georgia]"></div>
<div class="font-['Gill_Sans']"></div>
<div class="font-[300]"></div>
<div class="font-[family:var(--value)]"></div>
<div class="font-[weight:var(--value)]"></div>
```

**Output:**
```css
.font-\[Georgia\] {
    font-family: Georgia
}
.font-\[\'Gill_Sans\'\] {
    font-family: 'Gill Sans'
}
.font-\[family\:var\(--value\)\] {
    font-family: var(--value)
}
.font-\[300\] {
    font-weight: 300
}
.font-\[weight\:var\(--value\)\] {
    font-weight: var(--value)
}
```

---

### Outline

The outline plugin can be configured as an array in the config, therefore I mimicked this behaviour in the arbitrary value support for this plugin as well. The first argument will be the `outline`, the second argument will be the `outline-offset` which defaults to `0`.

**Input:**
```html
<div class="outline-[2px_solid_black]"></div>
<div class="outline-[2px_solid_black,2px]"></div>
```

**Output:**
```css
.outline-\[2px_solid_black\] {
    outline: 2px solid black;
    outline-offset: 0
}
.outline-\[2px_solid_black\2c 2px\] {
    outline: 2px solid black;
    outline-offset: 2px
}
```



Patch:
diff --git a/src/corePlugins.js b/src/corePlugins.js
index e801e462..e8dccc8b 100644
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -16,9 +16,6 @@ import {
   transformAllSelectors,
   transformAllClasses,
   transformLastClasses,
-  asLength,
-  asURL,
-  asLookupValue,
 } from './util/pluginUtils'
 import packageJson from '../package.json'
 import log from './util/log'
@@ -520,35 +517,19 @@ export let position = ({ addUtilities }) => {
   })
 }
 
-export let inset = ({ matchUtilities, theme }) => {
-  let options = {
-    values: theme('inset'),
-    type: 'any',
-  }
-
-  matchUtilities(
-    { inset: (value) => ({ top: value, right: value, bottom: value, left: value }) },
-    options
-  )
-
-  matchUtilities(
-    {
-      'inset-x': (value) => ({ left: value, right: value }),
-      'inset-y': (value) => ({ top: value, bottom: value }),
-    },
-    options
-  )
-
-  matchUtilities(
-    {
-      top: (top) => ({ top }),
-      right: (right) => ({ right }),
-      bottom: (bottom) => ({ bottom }),
-      left: (left) => ({ left }),
-    },
-    options
-  )
-}
+export let inset = createUtilityPlugin('inset', [
+  ['inset', ['top', 'right', 'bottom', 'left']],
+  [
+    ['inset-x', ['left', 'right']],
+    ['inset-y', ['top', 'bottom']],
+  ],
+  [
+    ['top', ['top']],
+    ['right', ['right']],
+    ['bottom', ['bottom']],
+    ['left', ['left']],
+  ],
+])
 
 export let isolation = ({ addUtilities }) => {
   addUtilities({
@@ -633,12 +614,15 @@ export let display = ({ addUtilities }) => {
 }
 
 export let aspectRatio = createUtilityPlugin('aspectRatio', [['aspect', ['aspect-ratio']]])
+
 export let height = createUtilityPlugin('height', [['h', ['height']]])
 export let maxHeight = createUtilityPlugin('maxHeight', [['max-h', ['maxHeight']]])
 export let minHeight = createUtilityPlugin('minHeight', [['min-h', ['minHeight']]])
+
 export let width = createUtilityPlugin('width', [['w', ['width']]])
 export let minWidth = createUtilityPlugin('minWidth', [['min-w', ['minWidth']]])
 export let maxWidth = createUtilityPlugin('maxWidth', [['max-w', ['maxWidth']]])
+
 export let flex = createUtilityPlugin('flex')
 export let flexShrink = createUtilityPlugin('flexShrink', [['flex-shrink', ['flex-shrink']]])
 export let flexGrow = createUtilityPlugin('flexGrow', [['flex-grow', ['flex-grow']]])
@@ -992,7 +976,7 @@ export let space = ({ matchUtilities, addUtilities, theme }) => {
         }
       },
     },
-    { values: theme('space'), type: 'any' }
+    { values: theme('space') }
   )
 
   addUtilities({
@@ -1029,7 +1013,7 @@ export let divideWidth = ({ matchUtilities, addUtilities, theme }) => {
         }
       },
     },
-    { values: theme('divideWidth'), type: 'length' }
+    { values: theme('divideWidth'), type: ['line-width', 'length'] }
   )
 
   addUtilities({
@@ -1089,7 +1073,7 @@ export let divideOpacity = ({ matchUtilities, theme }) => {
         return { [`& > :not([hidden]) ~ :not([hidden])`]: { '--tw-divide-opacity': value } }
       },
     },
-    { values: theme('divideOpacity'), type: 'any' }
+    { values: theme('divideOpacity') }
   )
 }
 
@@ -1215,7 +1199,7 @@ export let borderWidth = createUtilityPlugin(
       ['border-l', [['@defaults border-width', {}], 'border-left-width']],
     ],
   ],
-  { resolveArbitraryValue: asLength }
+  { type: ['line-width', 'length'] }
 )
 
 export let borderStyle = ({ addUtilities }) => {
@@ -1265,7 +1249,7 @@ export let borderColor = ({ addBase, matchUtilities, theme, corePlugins }) => {
     },
     {
       values: (({ DEFAULT: _, ...colors }) => colors)(flattenColorPalette(theme('borderColor'))),
-      type: 'color',
+      type: ['color'],
     }
   )
 
@@ -1362,7 +1346,7 @@ export let backgroundOpacity = createUtilityPlugin('backgroundOpacity', [
 export let backgroundImage = createUtilityPlugin(
   'backgroundImage',
   [['bg', ['background-image']]],
-  { resolveArbitraryValue: [asLookupValue, asURL] }
+  { type: ['lookup', 'image', 'url'] }
 )
 export let gradientColorStops = (() => {
   function transparentTo(value) {
@@ -1415,7 +1399,7 @@ export let boxDecorationBreak = ({ addUtilities }) => {
 }
 
 export let backgroundSize = createUtilityPlugin('backgroundSize', [['bg', ['background-size']]], {
-  resolveArbitraryValue: asLookupValue,
+  type: ['lookup', 'length', 'percentage'],
 })
 
 export let backgroundAttachment = ({ addUtilities }) => {
@@ -1438,7 +1422,7 @@ export let backgroundClip = ({ addUtilities }) => {
 export let backgroundPosition = createUtilityPlugin(
   'backgroundPosition',
   [['bg', ['background-position']]],
-  { resolveArbitraryValue: asLookupValue }
+  { type: ['lookup', 'position'] }
 )
 
 export let backgroundRepeat = ({ addUtilities }) => {
@@ -1478,12 +1462,12 @@ export let stroke = ({ matchUtilities, theme }) => {
         return { stroke: toColorValue(value) }
       },
     },
-    { values: flattenColorPalette(theme('stroke')), type: 'color' }
+    { values: flattenColorPalette(theme('stroke')), type: ['color', 'url'] }
   )
 }
 
 export let strokeWidth = createUtilityPlugin('strokeWidth', [['stroke', ['stroke-width']]], {
-  resolveArbitraryValue: [asLength, asURL],
+  type: ['length', 'number', 'percentage'],
 })
 
 export let objectFit = ({ addUtilities }) => {
@@ -1534,18 +1518,11 @@ export let verticalAlign = ({ addUtilities, matchUtilities }) => {
     '.align-super': { 'vertical-align': 'super' },
   })
 
-  matchUtilities(
-    {
-      align: (value) => ({
-        'vertical-align': value,
-      }),
-    },
-    { values: {}, type: 'any' }
-  )
+  matchUtilities({ align: (value) => ({ 'vertical-align': value }) })
 }
 
 export let fontFamily = createUtilityPlugin('fontFamily', [['font', ['fontFamily']]], {
-  resolveArbitraryValue: asLookupValue,
+  type: ['lookup', 'generic-name', 'family-name'],
 })
 
 export let fontSize = ({ matchUtilities, theme }) => {
@@ -1564,12 +1541,12 @@ export let fontSize = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('fontSize'), type: 'length' }
+    { values: theme('fontSize'), type: ['absolute-size', 'relative-size', 'length', 'percentage'] }
   )
 }
 
 export let fontWeight = createUtilityPlugin('fontWeight', [['font', ['fontWeight']]], {
-  resolveArbitraryValue: asLookupValue,
+  type: ['lookup', 'number'],
 })
 
 export let textTransform = ({ addUtilities }) => {
@@ -1691,7 +1668,7 @@ export let placeholderOpacity = ({ matchUtilities, theme }) => {
         return { ['&::placeholder']: { '--tw-placeholder-opacity': value } }
       },
     },
-    { values: theme('placeholderOpacity'), type: 'any' }
+    { values: theme('placeholderOpacity') }
   )
 }
 
@@ -1799,12 +1776,13 @@ export let outline = ({ matchUtilities, theme }) => {
   matchUtilities(
     {
       outline: (value) => {
+        value = Array.isArray(value) ? value : value.split(',')
         let [outline, outlineOffset = '0'] = Array.isArray(value) ? value : [value]
 
         return { outline, 'outline-offset': outlineOffset }
       },
     },
-    { values: theme('outline'), type: 'any' }
+    { values: theme('outline') }
   )
 }
 
@@ -1881,7 +1859,7 @@ export let ringOpacity = createUtilityPlugin(
 export let ringOffsetWidth = createUtilityPlugin(
   'ringOffsetWidth',
   [['ring-offset', ['--tw-ring-offset-width']]],
-  { resolveArbitraryValue: asLength }
+  { type: 'length' }
 )
 
 export let ringOffsetColor = ({ matchUtilities, theme }) => {
@@ -1908,7 +1886,7 @@ export let blur = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('blur'), type: 'any' }
+    { values: theme('blur') }
   )
 }
 
@@ -1923,7 +1901,7 @@ export let brightness = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('brightness'), type: 'any' }
+    { values: theme('brightness') }
   )
 }
 
@@ -1938,7 +1916,7 @@ export let contrast = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('contrast'), type: 'any' }
+    { values: theme('contrast') }
   )
 }
 
@@ -1970,7 +1948,7 @@ export let grayscale = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('grayscale'), type: 'any' }
+    { values: theme('grayscale') }
   )
 }
 
@@ -1985,7 +1963,7 @@ export let hueRotate = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('hueRotate'), type: 'any' }
+    { values: theme('hueRotate') }
   )
 }
 
@@ -2000,7 +1978,7 @@ export let invert = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('invert'), type: 'any' }
+    { values: theme('invert') }
   )
 }
 
@@ -2015,7 +1993,7 @@ export let saturate = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('saturate'), type: 'any' }
+    { values: theme('saturate') }
   )
 }
 
@@ -2030,7 +2008,7 @@ export let sepia = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('sepia'), type: 'any' }
+    { values: theme('sepia') }
   )
 }
 
@@ -2076,7 +2054,7 @@ export let backdropBlur = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropBlur'), type: 'any' }
+    { values: theme('backdropBlur') }
   )
 }
 
@@ -2091,7 +2069,7 @@ export let backdropBrightness = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropBrightness'), type: 'any' }
+    { values: theme('backdropBrightness') }
   )
 }
 
@@ -2106,7 +2084,7 @@ export let backdropContrast = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropContrast'), type: 'any' }
+    { values: theme('backdropContrast') }
   )
 }
 
@@ -2121,7 +2099,7 @@ export let backdropGrayscale = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropGrayscale'), type: 'any' }
+    { values: theme('backdropGrayscale') }
   )
 }
 
@@ -2136,7 +2114,7 @@ export let backdropHueRotate = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropHueRotate'), type: 'any' }
+    { values: theme('backdropHueRotate') }
   )
 }
 
@@ -2151,7 +2129,7 @@ export let backdropInvert = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropInvert'), type: 'any' }
+    { values: theme('backdropInvert') }
   )
 }
 
@@ -2166,7 +2144,7 @@ export let backdropOpacity = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropOpacity'), type: 'any' }
+    { values: theme('backdropOpacity') }
   )
 }
 
@@ -2181,7 +2159,7 @@ export let backdropSaturate = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropSaturate'), type: 'any' }
+    { values: theme('backdropSaturate') }
   )
 }
 
@@ -2196,7 +2174,7 @@ export let backdropSepia = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('backdropSepia'), type: 'any' }
+    { values: theme('backdropSepia') }
   )
 }
 
@@ -2252,7 +2230,7 @@ export let transitionProperty = ({ matchUtilities, theme }) => {
         }
       },
     },
-    { values: theme('transitionProperty'), type: 'any' }
+    { values: theme('transitionProperty') }
   )
 }
 
diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js
index 3ecdcb3b..bdc8e68d 100644
--- a/src/lib/expandTailwindAtRules.js
+++ b/src/lib/expandTailwindAtRules.js
@@ -7,6 +7,8 @@ let env = sharedState.env
 let contentMatchCache = sharedState.contentMatchCache
 
 const PATTERNS = [
+  /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
+  /([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source, // font-["some_font",sans-serif]
   /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
   /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
   /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
diff --git a/src/util/createUtilityPlugin.js b/src/util/createUtilityPlugin.js
index 4a9dadc5..1760a05c 100644
--- a/src/util/createUtilityPlugin.js
+++ b/src/util/createUtilityPlugin.js
@@ -1,19 +1,9 @@
 import transformThemeValue from './transformThemeValue'
-import { asValue, asColor, asAngle, asLength, asURL, asLookupValue } from '../util/pluginUtils'
-
-let asMap = new Map([
-  [asValue, 'any'],
-  [asColor, 'color'],
-  [asAngle, 'angle'],
-  [asLength, 'length'],
-  [asURL, 'url'],
-  [asLookupValue, 'lookup'],
-])
 
 export default function createUtilityPlugin(
   themeKey,
   utilityVariations = [[themeKey, [themeKey]]],
-  { filterDefault = false, resolveArbitraryValue = asValue } = {}
+  { filterDefault = false, type = 'any' } = {}
 ) {
   let transformValue = transformThemeValue(themeKey)
   return function ({ matchUtilities, theme }) {
@@ -39,9 +29,7 @@ export default function createUtilityPlugin(
                 Object.entries(theme(themeKey) ?? {}).filter(([modifier]) => modifier !== 'DEFAULT')
               )
             : theme(themeKey),
-          type: Array.isArray(resolveArbitraryValue)
-            ? resolveArbitraryValue.map((typeResolver) => asMap.get(typeResolver) ?? 'any')
-            : asMap.get(resolveArbitraryValue) ?? 'any',
+          type,
         }
       )
     }
diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js
new file mode 100644
index 00000000..e1b616a1
--- /dev/null
+++ b/src/util/dataTypes.js
@@ -0,0 +1,216 @@
+import { parseColor } from './color'
+
+// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
+
+let COMMA = /,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
+let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located between brackets. E.g.: `rgba(255,_255,_255)_black` these don't count.
+
+// This is not a data type, but rather a function that can normalize the
+// correct values.
+export function normalize(value) {
+  // Convert `_` to ` `, except for escaped underscores `\_`
+  value = value
+    .replace(
+      /([^\\])_+/g,
+      (fullMatch, characterBefore) => characterBefore + ' '.repeat(fullMatch.length - 1)
+    )
+    .replace(/^_/g, ' ')
+    .replace(/\\_/g, '_')
+
+  // Remove leftover whitespace
+  value = value.trim()
+
+  // Keep raw strings if it starts with `url(`
+  if (value.startsWith('url(')) return value
+
+  // Add spaces around operators inside calc() that do not follow an operator
+  // or '('.
+  return value.replace(
+    /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
+    '$1 $2 '
+  )
+}
+
+export function url(value) {
+  return value.startsWith('url(')
+}
+
+export function number(value) {
+  return !isNaN(Number(value))
+}
+
+export function percentage(value) {
+  return /%$/g.test(value) || /^calc\(.+?%\)/g.test(value)
+}
+
+let lengthUnits = [
+  'cm',
+  'mm',
+  'Q',
+  'in',
+  'pc',
+  'pt',
+  'px',
+  'em',
+  'ex',
+  'ch',
+  'rem',
+  'lh',
+  'vw',
+  'vh',
+  'vmin',
+  'vmax',
+]
+let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`
+export function length(value) {
+  return (
+    new RegExp(`${lengthUnitsPattern}$`).test(value) ||
+    new RegExp(`^calc\\(.+?${lengthUnitsPattern}`).test(value)
+  )
+}
+
+let lineWidths = new Set(['thin', 'medium', 'thick'])
+export function lineWidth(value) {
+  return lineWidths.has(value)
+}
+
+export function color(value) {
+  let colors = 0
+
+  let result = value.split(UNDERSCORE).every((part) => {
+    part = normalize(part)
+
+    if (part.startsWith('var(')) return true
+    if (parseColor(part) !== null) return colors++, true
+
+    return false
+  })
+
+  if (!result) return false
+  return colors > 0
+}
+
+export function image(value) {
+  let images = 0
+  let result = value.split(COMMA).every((part) => {
+    part = normalize(part)
+
+    if (part.startsWith('var(')) return true
+    if (
+      url(part) ||
+      gradient(part) ||
+      ['element(', 'image(', 'cross-fade(', 'image-set('].some((fn) => part.startsWith(fn))
+    ) {
+      images++
+      return true
+    }
+
+    return false
+  })
+
+  if (!result) return false
+  return images > 0
+}
+
+let gradientTypes = new Set([
+  'linear-gradient',
+  'radial-gradient',
+  'repeating-linear-gradient',
+  'repeating-radial-gradient',
+  'conic-gradient',
+])
+export function gradient(value) {
+  value = normalize(value)
+
+  for (let type of gradientTypes) {
+    if (value.startsWith(`${type}(`)) {
+      return true
+    }
+  }
+  return false
+}
+
+let validPositions = new Set(['center', 'top', 'right', 'bottom', 'left'])
+export function position(value) {
+  let positions = 0
+  let result = value.split(UNDERSCORE).every((part) => {
+    part = normalize(part)
+
+    if (part.startsWith('var(')) return true
+    if (validPositions.has(part) || length(part) || percentage(part)) {
+      positions++
+      return true
+    }
+
+    return false
+  })
+
+  if (!result) return false
+  return positions > 0
+}
+
+export function familyName(value) {
+  let fonts = 0
+  let result = value.split(COMMA).every((part) => {
+    part = normalize(part)
+
+    if (part.startsWith('var(')) return true
+
+    // If it contains spaces, then it should be quoted
+    if (part.includes(' ')) {
+      if (!/(['"])([^"']+)\1/g.test(part)) {
+        return false
+      }
+    }
+
+    // If it starts with a number, it's invalid
+    if (/^\d/g.test(part)) {
+      return false
+    }
+
+    fonts++
+
+    return true
+  })
+
+  if (!result) return false
+  return fonts > 0
+}
+
+let genericNames = new Set([
+  'serif',
+  'sans-serif',
+  'monospace',
+  'cursive',
+  'fantasy',
+  'system-ui',
+  'ui-serif',
+  'ui-sans-serif',
+  'ui-monospace',
+  'ui-rounded',
+  'math',
+  'emoji',
+  'fangsong',
+])
+export function genericName(value) {
+  return genericNames.has(value)
+}
+
+let absoluteSizes = new Set([
+  'xx-small',
+  'x-small',
+  'small',
+  'medium',
+  'large',
+  'x-large',
+  'x-large',
+  'xxx-large',
+])
+export function absoluteSize(value) {
+  return absoluteSizes.has(value)
+}
+
+let relativeSizes = new Set(['larger', 'smaller'])
+export function relativeSize(value) {
+  return relativeSizes.has(value)
+}
diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js
index ddd49900..73c4170a 100644
--- a/src/util/pluginUtils.js
+++ b/src/util/pluginUtils.js
@@ -2,7 +2,21 @@ import selectorParser from 'postcss-selector-parser'
 import escapeCommas from './escapeCommas'
 import { withAlphaValue } from './withAlphaVariable'
 import isKeyframeRule from './isKeyframeRule'
-import { parseColor } from './color'
+import {
+  normalize,
+  length,
+  number,
+  percentage,
+  url,
+  color as validateColor,
+  genericName,
+  familyName,
+  image,
+  absoluteSize,
+  relativeSize,
+  position,
+  lineWidth,
+} from './dataTypes'
 
 export function applyPseudoToMarker(selector, marker, state, join) {
   let states = [state]
@@ -159,7 +173,7 @@ export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
     return value
   }
 
-  if (modifier[0] !== '[' || modifier[modifier.length - 1] !== ']') {
+  if (!isArbitraryValue(modifier)) {
     return undefined
   }
 
@@ -169,32 +183,7 @@ export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
     return undefined
   }
 
-  // convert `_` to ` `, escept for escaped underscores `\_`
-  value = value
-    .replace(/([^\\])_/g, '$1 ')
-    .replace(/^_/g, ' ')
-    .replace(/\\_/g, '_')
-
-  // Keep raw strings if it starts with `url(`
-  if (value.startsWith('url(')) return value
-
-  // add spaces around operators inside calc() that do not follow an operator or (
-  return value.replace(
-    /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
-    '$1 $2 '
-  )
-}
-
-export function asUnit(modifier, units, lookup = {}) {
-  return asValue(modifier, lookup, {
-    validate: (value) => {
-      let unitsPattern = `(?:${units.join('|')})`
-      return (
-        new RegExp(`${unitsPattern}$`).test(value) ||
-        new RegExp(`^calc\\(.+?${unitsPattern}`).test(value)
-      )
-    },
-  })
+  return normalize(value)
 }
 
 function isArbitraryValue(input) {
@@ -230,58 +219,34 @@ export function asColor(modifier, lookup = {}, tailwindConfig = {}) {
     return withAlphaValue(lookup[color], tailwindConfig.theme.opacity[alpha])
   }
 
-  return asValue(modifier, lookup, {
-    validate: (value) => parseColor(value) !== null,
-  })
-}
-
-export function asAngle(modifier, lookup = {}) {
-  return asUnit(modifier, ['deg', 'grad', 'rad', 'turn'], lookup)
-}
-
-export function asURL(modifier, lookup = {}) {
-  return asValue(modifier, lookup, {
-    validate: (value) => value.startsWith('url('),
-  })
-}
-
-export function asLength(modifier, lookup = {}) {
-  return asUnit(
-    modifier,
-    [
-      'cm',
-      'mm',
-      'Q',
-      'in',
-      'pc',
-      'pt',
-      'px',
-      'em',
-      'ex',
-      'ch',
-      'rem',
-      'lh',
-      'vw',
-      'vh',
-      'vmin',
-      'vmax',
-      '%',
-    ],
-    lookup
-  )
+  return asValue(modifier, lookup, { validate: validateColor })
 }
 
 export function asLookupValue(modifier, lookup = {}) {
   return lookup[modifier]
 }
 
+function guess(validate) {
+  return (modifier, lookup) => {
+    return asValue(modifier, lookup, { validate })
+  }
+}
+
 let typeMap = {
   any: asValue,
   color: asColor,
-  angle: asAngle,
-  length: asLength,
-  url: asURL,
+  url: guess(url),
+  image: guess(image),
+  length: guess(length),
+  percentage: guess(percentage),
+  position: guess(position),
   lookup: asLookupValue,
+  'generic-name': guess(genericName),
+  'family-name': guess(familyName),
+  number: guess(number),
+  'line-width': guess(lineWidth),
+  'absolute-size': guess(absoluteSize),
+  'relative-size': guess(relativeSize),
 }
 
 let supportedTypes = Object.keys(typeMap)
@@ -292,9 +257,7 @@ function splitAtFirst(input, delim) {
   return [input.slice(0, idx), input.slice(idx + 1)]
 }
 
-export function coerceValue(type, modifier, values, tailwindConfig) {
-  let [scaleType, arbitraryType = scaleType] = [].concat(type)
-
+export function coerceValue(types, modifier, values, tailwindConfig) {
   if (isArbitraryValue(modifier)) {
     let [explicitType, value] = splitAtFirst(modifier.slice(1, -1), ':')
 
@@ -305,9 +268,13 @@ export function coerceValue(type, modifier, values, tailwindConfig) {
     if (value.length > 0 && supportedTypes.includes(explicitType)) {
       return [asValue(`[${value}]`, values, tailwindConfig), explicitType]
     }
+  }
 
-    return [typeMap[arbitraryType](modifier, values, tailwindConfig), arbitraryType]
+  // Find first matching type
+  for (let type of [].concat(types)) {
+    let result = typeMap[type](modifier, values, tailwindConfig)
+    if (result) return [result, type]
   }
 
-  return [typeMap[scaleType](modifier, values, tailwindConfig), scaleType]
+  return []
 }
diff --git a/stubs/defaultConfig.stub.js b/stubs/defaultConfig.stub.js
index 3ce4b4e5..98f7fc9b 100644
--- a/stubs/defaultConfig.stub.js
+++ b/stubs/defaultConfig.stub.js
@@ -111,9 +111,9 @@ module.exports = {
       bounce: 'bounce 1s infinite',
     },
     aspectRatio: {
-      'auto': 'auto',
-      'square': '1 / 1',
-      'video': '16 / 9',
+      auto: 'auto',
+      square: '1 / 1',
+      video: '16 / 9',
     },
     backdropBlur: (theme) => theme('blur'),
     backdropBrightness: (theme) => theme('brightness'),
@@ -847,10 +847,10 @@ module.exports = {
       max: 'max-content',
     }),
     willChange: {
-      'auto': 'auto',
-      'scroll': 'scroll-position',
-      'contents': 'contents',
-      'transform': 'transform',
+      auto: 'auto',
+      scroll: 'scroll-position',
+      contents: 'contents',
+      transform: 'transform',
     },
     zIndex: {
       auto: 'auto',


Test patch:
diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css
index 6d915765..7bb79dbb 100644
--- a/tests/arbitrary-values.test.css
+++ b/tests/arbitrary-values.test.css
@@ -4,6 +4,64 @@
   bottom: 11px;
   left: 11px;
 }
+.inset-\[var\(--value\)\] {
+  top: var(--value);
+  right: var(--value);
+  bottom: var(--value);
+  left: var(--value);
+}
+.inset-x-\[11px\] {
+  left: 11px;
+  right: 11px;
+}
+.inset-x-\[var\(--value\)\] {
+  left: var(--value);
+  right: var(--value);
+}
+.inset-y-\[11px\] {
+  top: 11px;
+  bottom: 11px;
+}
+.inset-y-\[var\(--value\)\] {
+  top: var(--value);
+  bottom: var(--value);
+}
+.top-\[11px\] {
+  top: 11px;
+}
+.top-\[var\(--value\)\] {
+  top: var(--value);
+}
+.right-\[11px\] {
+  right: 11px;
+}
+.right-\[var\(--value\)\] {
+  right: var(--value);
+}
+.bottom-\[11px\] {
+  bottom: 11px;
+}
+.bottom-\[var\(--value\)\] {
+  bottom: var(--value);
+}
+.left-\[11px\] {
+  left: 11px;
+}
+.left-\[var\(--value\)\] {
+  left: var(--value);
+}
+.z-\[123\] {
+  z-index: 123;
+}
+.z-\[var\(--value\)\] {
+  z-index: var(--value);
+}
+.order-\[4\] {
+  order: 4;
+}
+.order-\[var\(--value\)\] {
+  order: var(--value);
+}
 .col-\[7\] {
   grid-column: 7;
 }
@@ -157,6 +215,25 @@
 .flex-grow-\[var\(--grow\)\] {
   flex-grow: var(--grow);
 }
+.origin-\[50px_50px\] {
+  transform-origin: 50px 50px;
+}
+.translate-x-\[12\%\] {
+  --tw-translate-x: 12%;
+  transform: var(--tw-transform);
+}
+.translate-x-\[var\(--value\)\] {
+  --tw-translate-x: var(--value);
+  transform: var(--tw-transform);
+}
+.translate-y-\[12\%\] {
+  --tw-translate-y: 12%;
+  transform: var(--tw-transform);
+}
+.translate-y-\[var\(--value\)\] {
+  --tw-translate-y: var(--value);
+  transform: var(--tw-transform);
+}
 .rotate-\[23deg\] {
   --tw-rotate: 23deg;
   transform: var(--tw-transform);
@@ -177,16 +254,77 @@
   --tw-skew-x: 3px;
   transform: var(--tw-transform);
 }
+.skew-x-\[var\(--value\)\] {
+  --tw-skew-x: var(--value);
+  transform: var(--tw-transform);
+}
 .skew-y-\[3px\] {
   --tw-skew-y: 3px;
   transform: var(--tw-transform);
 }
+.skew-y-\[var\(--value\)\] {
+  --tw-skew-y: var(--value);
+  transform: var(--tw-transform);
+}
+.scale-\[0\.7\] {
+  --tw-scale-x: 0.7;
+  --tw-scale-y: 0.7;
+  transform: var(--tw-transform);
+}
+.scale-\[var\(--value\)\] {
+  --tw-scale-x: var(--value);
+  --tw-scale-y: var(--value);
+  transform: var(--tw-transform);
+}
+.scale-x-\[0\.7\] {
+  --tw-scale-x: 0.7;
+  transform: var(--tw-transform);
+}
+.scale-x-\[var\(--value\)\] {
+  --tw-scale-x: var(--value);
+  transform: var(--tw-transform);
+}
+.scale-y-\[0\.7\] {
+  --tw-scale-y: 0.7;
+  transform: var(--tw-transform);
+}
+.scale-y-\[var\(--value\)\] {
+  --tw-scale-y: var(--value);
+  transform: var(--tw-transform);
+}
+.animate-\[pong_1s_cubic-bezier\(0\2c 0\2c 0\.2\2c 1\)_infinite\] {
+  animation: pong 1s cubic-bezier(0, 0, 0.2, 1) infinite;
+}
+.animate-\[var\(--value\)\] {
+  animation: var(--value);
+}
+.cursor-\[pointer\] {
+  cursor: pointer;
+}
+.cursor-\[url\(hand\.cur\)_2_2\2c pointer\] {
+  cursor: url(hand.cur) 2 2, pointer;
+}
+.cursor-\[var\(--value\)\] {
+  cursor: var(--value);
+}
+.list-\[\'\\1f44d\'\] {
+  list-style-type: '\1F44D';
+}
+.list-\[var\(--value\)\] {
+  list-style-type: var(--value);
+}
 .columns-\[20\] {
   columns: 20;
 }
 .columns-\[var\(--columns\)\] {
   columns: var(--columns);
 }
+.auto-cols-\[minmax\(10px\2c auto\)\] {
+  grid-auto-columns: minmax(10px, auto);
+}
+.auto-rows-\[minmax\(10px\2c auto\)\] {
+  grid-auto-rows: minmax(10px, auto);
+}
 .grid-cols-\[200px\2c repeat\(auto-fill\2c minmax\(15\%\2c 100px\)\)\2c 300px\] {
   grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px;
 }
@@ -196,6 +334,24 @@
 .grid-rows-\[200px\2c repeat\(auto-fill\2c minmax\(15\%\2c 100px\)\)\2c 300px\] {
   grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px;
 }
+.gap-\[20px\] {
+  gap: 20px;
+}
+.gap-\[var\(--value\)\] {
+  gap: var(--value);
+}
+.gap-x-\[20px\] {
+  column-gap: 20px;
+}
+.gap-x-\[var\(--value\)\] {
+  column-gap: var(--value);
+}
+.gap-y-\[20px\] {
+  row-gap: 20px;
+}
+.gap-y-\[var\(--value\)\] {
+  row-gap: var(--value);
+}
 .space-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
   --tw-space-x-reverse: 0;
   margin-right: calc(20cm * var(--tw-space-x-reverse));
@@ -206,6 +362,46 @@
   margin-right: calc(calc(20% - 1cm) * var(--tw-space-x-reverse));
   margin-left: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-x-reverse)));
 }
+.space-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-space-y-reverse: 0;
+  margin-top: calc(20cm * calc(1 - var(--tw-space-y-reverse)));
+  margin-bottom: calc(20cm * var(--tw-space-y-reverse));
+}
+.space-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-space-y-reverse: 0;
+  margin-top: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-y-reverse)));
+  margin-bottom: calc(calc(20% - 1cm) * var(--tw-space-y-reverse));
+}
+.divide-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-x-reverse: 0;
+  border-right-width: calc(20cm * var(--tw-divide-x-reverse));
+  border-left-width: calc(20cm * calc(1 - var(--tw-divide-x-reverse)));
+}
+.divide-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-x-reverse: 0;
+  border-right-width: calc(calc(20% - 1cm) * var(--tw-divide-x-reverse));
+  border-left-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-x-reverse)));
+}
+.divide-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-y-reverse: 0;
+  border-top-width: calc(20cm * calc(1 - var(--tw-divide-y-reverse)));
+  border-bottom-width: calc(20cm * var(--tw-divide-y-reverse));
+}
+.divide-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-y-reverse: 0;
+  border-top-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-y-reverse)));
+  border-bottom-width: calc(calc(20% - 1cm) * var(--tw-divide-y-reverse));
+}
+.divide-\[black\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-opacity: 1;
+  border-color: rgb(0 0 0 / var(--tw-divide-opacity));
+}
+.divide-opacity-\[0\.8\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-opacity: 0.8;
+}
+.divide-opacity-\[var\(--value\)\] > :not([hidden]) ~ :not([hidden]) {
+  --tw-divide-opacity: var(--value);
+}
 .rounded-\[11px\] {
   border-radius: 11px;
 }
@@ -240,10 +436,77 @@
 .border-\[2\.5px\] {
   border-width: 2.5px;
 }
+.border-\[length\:var\(--value\)\] {
+  border-width: var(--value);
+}
+.border-t-\[2\.5px\] {
+  border-top-width: 2.5px;
+}
+.border-t-\[length\:var\(--value\)\] {
+  border-top-width: var(--value);
+}
+.border-r-\[2\.5px\] {
+  border-right-width: 2.5px;
+}
+.border-r-\[length\:var\(--value\)\] {
+  border-right-width: var(--value);
+}
+.border-b-\[2\.5px\] {
+  border-bottom-width: 2.5px;
+}
+.border-b-\[length\:var\(--value\)\] {
+  border-bottom-width: var(--value);
+}
+.border-l-\[2\.5px\] {
+  border-left-width: 2.5px;
+}
+.border-l-\[length\:var\(--value\)\] {
+  border-left-width: var(--value);
+}
 .border-\[\#f00\] {
   --tw-border-opacity: 1;
   border-color: rgb(255 0 0 / var(--tw-border-opacity));
 }
+.border-\[red_black\] {
+  border-color: red black;
+}
+.border-\[color\:var\(--value\)\] {
+  border-color: var(--value);
+}
+.border-t-\[\#f00\] {
+  --tw-border-opacity: 1;
+  border-top-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-t-\[color\:var\(--value\)\] {
+  border-top-color: var(--value);
+}
+.border-r-\[\#f00\] {
+  --tw-border-opacity: 1;
+  border-right-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-r-\[color\:var\(--value\)\] {
+  border-right-color: var(--value);
+}
+.border-b-\[\#f00\] {
+  --tw-border-opacity: 1;
+  border-bottom-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-b-\[color\:var\(--value\)\] {
+  border-bottom-color: var(--value);
+}
+.border-l-\[\#f00\] {
+  --tw-border-opacity: 1;
+  border-left-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-l-\[color\:var\(--value\)\] {
+  border-left-color: var(--value);
+}
+.border-opacity-\[0\.8\] {
+  --tw-border-opacity: 0.8;
+}
+.border-opacity-\[var\(--value\)\] {
+  --tw-border-opacity: var(--value);
+}
 .bg-\[\#0f0\] {
   --tw-bg-opacity: 1;
   background-color: rgb(0 255 0 / var(--tw-bg-opacity));
@@ -262,6 +525,13 @@
 .bg-\[rgba\(123\2c 123\2c 123\2c 0\.5\)\] {
   background-color: rgba(123, 123, 123, 0.5);
 }
+.bg-\[rgb\(123\2c _456\2c _123\)_black\] {
+  background-color: rgb(123, 456, 123) black;
+}
+.bg-\[rgb\(123_456_789\)\] {
+  --tw-bg-opacity: 1;
+  background-color: rgb(123 456 789 / var(--tw-bg-opacity));
+}
 .bg-\[hsl\(0\2c 100\%\2c 50\%\)\] {
   --tw-bg-opacity: 1;
   background-color: hsl(0 100% 50% / var(--tw-bg-opacity));
@@ -269,6 +539,12 @@
 .bg-\[hsla\(0\2c 100\%\2c 50\%\2c 0\.3\)\] {
   background-color: hsla(0, 100%, 50%, 0.3);
 }
+.bg-\[\#0f0_var\(--value\)\] {
+  background-color: #0f0 var(--value);
+}
+.bg-\[color\:var\(--value1\)_var\(--value2\)\] {
+  background-color: var(--value1) var(--value2);
+}
 .bg-opacity-\[0\.11\] {
   --tw-bg-opacity: 0.11;
 }
@@ -281,6 +557,24 @@
 .bg-\[url\:var\(--url\)\] {
   background-image: var(--url);
 }
+.bg-\[linear-gradient\(\#eee\2c \#fff\)\] {
+  background-image: linear-gradient(#eee, #fff);
+}
+.bg-\[linear-gradient\(\#eee\2c
+  \#fff\)\2c
+  conic-gradient\(red\2c
+  orange\2c
+  yellow\2c
+  green\2c
+  blue\)\] {
+  background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, yellow, green, blue);
+}
+.bg-\[image\(\)\2c var\(--value\)\] {
+  background-image: image(), var(--value);
+}
+.bg-\[image\:var\(--value\)\2c var\(--value\)\] {
+  background-image: var(--value), var(--value);
+}
 .from-\[\#da5b66\] {
   --tw-gradient-from: #da5b66;
   --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgb(218 91 102 / 0));
@@ -302,17 +596,41 @@
 .to-\[var\(--color\)\] {
   --tw-gradient-to: var(--color);
 }
+.bg-\[length\:200px_100px\] {
+  background-size: 200px 100px;
+}
+.bg-\[length\:var\(--value\)\] {
+  background-size: var(--value);
+}
+.bg-\[position\:200px_100px\] {
+  background-position: 200px 100px;
+}
+.bg-\[position\:var\(--value\)\] {
+  background-position: var(--value);
+}
 .fill-\[\#da5b66\] {
   fill: #da5b66;
 }
-.fill-\[var\(--color\)\] {
-  fill: var(--color);
+.fill-\[var\(--value\)\] {
+  fill: var(--value);
+}
+.fill-\[url\(\#icon-gradient\)\] {
+  fill: url(#icon-gradient);
 }
 .stroke-\[\#da5b66\] {
   stroke: #da5b66;
 }
+.stroke-\[color\:var\(--value\)\] {
+  stroke: var(--value);
+}
 .stroke-\[url\(\#icon-gradient\)\] {
-  stroke-width: url(#icon-gradient);
+  stroke: url(#icon-gradient);
+}
+.stroke-\[20px\] {
+  stroke-width: 20px;
+}
+.stroke-\[length\:var\(--value\)\] {
+  stroke-width: var(--value);
 }
 .object-\[50\%\2c 50\%\] {
   object-position: 50% 50%;
@@ -323,8 +641,31 @@
 .object-\[var\(--position\)\] {
   object-position: var(--position);
 }
-.p-\[var\(--app-padding\)\] {
-  padding: var(--app-padding);
+.p-\[7px\] {
+  padding: 7px;
+}
+.px-\[7px\] {
+  padding-left: 7px;
+  padding-right: 7px;
+}
+.py-\[7px\] {
+  padding-top: 7px;
+  padding-bottom: 7px;
+}
+.pt-\[7px\] {
+  padding-top: 7px;
+}
+.pr-\[7px\] {
+  padding-right: 7px;
+}
+.pb-\[7px\] {
+  padding-bottom: 7px;
+}
+.pl-\[7px\] {
+  padding-left: 7px;
+}
+.pt-\[clamp\(30px\2c 100px\)\] {
+  padding-top: clamp(30px, 100px);
 }
 .indent-\[50\%\] {
   text-indent: 50%;
@@ -335,40 +676,130 @@
 .align-\[10em\] {
   vertical-align: 10em;
 }
+.font-\[Georgia\2c serif\] {
+  font-family: Georgia, serif;
+}
+.font-\[\'Gill_Sans\'\] {
+  font-family: 'Gill Sans';
+}
+.font-\[sans-serif\2c serif\] {
+  font-family: sans-serif, serif;
+}
+.font-\[family-name\:var\(--value\)\] {
+  font-family: var(--value);
+}
+.font-\[serif\2c var\(--value\)\] {
+  font-family: serif, var(--value);
+}
+.font-\[\'Some_Font\'\2c sans-serif\] {
+  font-family: 'Some Font', sans-serif;
+}
+.font-\[\'Some_Font\'\2c \'Some_Other_Font\'\] {
+  font-family: 'Some Font', 'Some Other Font';
+}
+.font-\[\'Some_Font\'\2c var\(--other-font\)\] {
+  font-family: 'Some Font', var(--other-font);
+}
 .text-\[2\.23rem\] {
   font-size: 2.23rem;
 }
 .text-\[length\:var\(--font-size\)\] {
   font-size: var(--font-size);
 }
+.font-\[300\] {
+  font-weight: 300;
+}
+.font-\[number\:lighter\] {
+  font-weight: lighter;
+}
+.font-\[number\:var\(--value\)\] {
+  font-weight: var(--value);
+}
 .leading-\[var\(--leading\)\] {
   line-height: var(--leading);
 }
 .tracking-\[var\(--tracking\)\] {
   letter-spacing: var(--tracking);
 }
+.text-\[black\] {
+  --tw-text-opacity: 1;
+  color: rgb(0 0 0 / var(--tw-text-opacity));
+}
+.text-\[rgb\(123\2c 123\2c 123\)\] {
+  --tw-text-opacity: 1;
+  color: rgb(123 123 123 / var(--tw-text-opacity));
+}
+.text-\[rgb\(123\2c _123\2c _123\)\] {
+  --tw-text-opacity: 1;
+  color: rgb(123 123 123 / var(--tw-text-opacity));
+}
+.text-\[rgb\(123_123_123\)\] {
+  --tw-text-opacity: 1;
+  color: rgb(123 123 123 / var(--tw-text-opacity));
+}
 .text-\[color\:var\(--color\)\] {
   color: var(--color);
 }
+.text-opacity-\[0\.8\] {
+  --tw-text-opacity: 0.8;
+}
+.text-opacity-\[var\(--value\)\] {
+  --tw-text-opacity: var(--value);
+}
 .placeholder-\[var\(--placeholder\)\]::placeholder {
   color: var(--placeholder);
 }
 .placeholder-opacity-\[var\(--placeholder-opacity\)\]::placeholder {
   --tw-placeholder-opacity: var(--placeholder-opacity);
 }
+.caret-\[black\] {
+  caret-color: black;
+}
+.caret-\[var\(--value\)\] {
+  caret-color: var(--value);
+}
 .accent-\[\#bada55\] {
   accent-color: #bada55;
 }
 .accent-\[var\(--accent-color\)\] {
   accent-color: var(--accent-color);
 }
+.opacity-\[0\.8\] {
+  opacity: 0.8;
+}
 .opacity-\[var\(--opacity\)\] {
   opacity: var(--opacity);
 }
+.shadow-\[0px_1px_2px_black\] {
+  --tw-shadow: 0px 1px 2px black;
+  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
+    var(--tw-shadow);
+}
+.shadow-\[var\(--value\)\] {
+  --tw-shadow: var(--value);
+  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
+    var(--tw-shadow);
+}
+.outline-\[2px_solid_black\] {
+  outline: 2px solid black;
+  outline-offset: 0;
+}
+.outline-\[2px_solid_black\2c 2px\] {
+  outline: 2px solid black;
+  outline-offset: 2px;
+}
 .outline-\[var\(--outline\)\] {
   outline: var(--outline);
   outline-offset: 0;
 }
+.outline-\[var\(--outline\)\2c 3px\] {
+  outline: var(--outline);
+  outline-offset: 3px;
+}
+.outline-\[2px_solid_black\2c var\(--outline-offset\)\] {
+  outline: 2px solid black;
+  outline-offset: var(--outline-offset);
+}
 .ring-\[10px\] {
   --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
     var(--tw-ring-offset-color);
@@ -376,22 +807,38 @@
     var(--tw-ring-color);
   box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
 }
+.ring-\[length\:\(var\(--value\)\)\] {
+  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
+    var(--tw-ring-offset-color);
+  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc((var(--value)) + var(--tw-ring-offset-width))
+    var(--tw-ring-color);
+  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
+}
 .ring-\[\#76ad65\] {
   --tw-ring-opacity: 1;
   --tw-ring-color: rgb(118 173 101 / var(--tw-ring-opacity));
 }
+.ring-\[color\:var\(--value\)\] {
+  --tw-ring-color: var(--value);
+}
 .ring-opacity-\[var\(--ring-opacity\)\] {
   --tw-ring-opacity: var(--ring-opacity);
 }
 .ring-offset-\[19rem\] {
   --tw-ring-offset-width: 19rem;
 }
+.ring-offset-\[length\:var\(--value\)\] {
+  --tw-ring-offset-width: var(--value);
+}
 .ring-offset-\[\#76ad65\] {
   --tw-ring-offset-color: #76ad65;
 }
 .ring-offset-\[\#ad672f\] {
   --tw-ring-offset-color: #ad672f;
 }
+.ring-offset-\[color\:var\(--value\)\] {
+  --tw-ring-offset-color: var(--value);
+}
 .blur-\[15px\] {
   --tw-blur: blur(15px);
   filter: var(--tw-filter);
@@ -404,6 +851,10 @@
   --tw-contrast: contrast(2.4);
   filter: var(--tw-filter);
 }
+.drop-shadow-\[0px_1px_2px_black\] {
+  --tw-drop-shadow: drop-shadow(0px 1px 2px black);
+  filter: var(--tw-filter);
+}
 .grayscale-\[0\.55\] {
   --tw-grayscale: grayscale(0.55);
   filter: var(--tw-filter);
diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html
index bab407ed..651aa68c 100644
--- a/tests/arbitrary-values.test.html
+++ b/tests/arbitrary-values.test.html
@@ -8,70 +8,142 @@
     <link rel="stylesheet" href="./tailwind.css" />
   </head>
   <body>
-    <div class="bg-[#0f0] bg-[#ff0000] bg-[#0000ffcc]"></div>
-    <div class="bg-[rgb(123,123,123)] bg-[rgba(123,123,123,0.5)]"></div>
-    <div class="bg-[hsl(0,100%,50%)] bg-[hsla(0,100%,50%,0.3)]"></div>
-    <div class="bg-[url('/path-to-image.png')] bg-[url:var(--url)]"></div>
-    <div class="bg-opacity-[0.11]"></div>
-    <div class="bg-opacity-[var(--value)]"></div>
-    <div class="border-[#f00]"></div>
-    <div class="border-[2.5px]"></div>
+    <div class="inset-[11px]"></div>
+    <div class="inset-[var(--value)]"></div>
+    <div class="inset-x-[11px]"></div>
+    <div class="inset-x-[var(--value)]"></div>
+    <div class="inset-y-[11px]"></div>
+    <div class="inset-y-[var(--value)]"></div>
+    <div class="top-[11px]"></div>
+    <div class="top-[var(--value)]"></div>
+    <div class="right-[11px]"></div>
+    <div class="right-[var(--value)]"></div>
+    <div class="bottom-[11px]"></div>
+    <div class="bottom-[var(--value)]"></div>
+    <div class="left-[11px]"></div>
+    <div class="left-[var(--value)]"></div>
+
+    <div class="z-[123]"></div>
+    <div class="z-[var(--value)]"></div>
+
+    <div class="order-[4]"></div>
+    <div class="order-[var(--value)]"></div>
+
+    <div class="col-[7]"></div>
+    <div class="col-end-[7]"></div>
+    <div class="col-start-[7]"></div>
+
+    <div class="row-[7]"></div>
+    <div class="row-end-[7]"></div>
+    <div class="row-start-[7]"></div>
+
+    <div class="m-[7px]"></div>
+    <div class="mx-[7px]"></div>
+    <div class="my-[7px]"></div>
+    <div class="mt-[7px]"></div>
+    <div class="mr-[7px]"></div>
+    <div class="mb-[7px]"></div>
+    <div class="ml-[7px]"></div>
+    <div class="mt-[clamp(30px,100px)]"></div>
+
     <div class="aspect-[16/9] aspect-[var(--aspect)]"></div>
+
+    <div class="h-[3.23rem]"></div>
+    <div class="h-[calc(100%+1rem)]"></div>
+    <div class="h-[var(--height)]"></div>
+
+    <div class="max-h-[3.23rem]"></div>
+    <div class="max-h-[calc(100%+1rem)]"></div>
+    <div class="max-h-[var(--height)]"></div>
+
+    <div class="min-h-[3.23rem]"></div>
+    <div class="min-h-[calc(100%+1rem)]"></div>
+    <div class="min-h-[var(--height)]"></div>
+
     <div class="w-[3.23rem]"></div>
     <div class="w-[calc(100%+1rem)]"></div>
     <div class="w-[calc(var(--10-10px,calc(-20px-(-30px--40px)))-50px)]"></div>
     <div class="w-[var(--width)]"></div>
     <div class="w-[var(--width,calc(100%+1rem))]"></div>
     <div class="w-[calc(100%/3-1rem*2)]"></div>
+
     <div class="min-w-[3.23rem]"></div>
     <div class="min-w-[calc(100%+1rem)]"></div>
     <div class="min-w-[var(--width)]"></div>
+
     <div class="max-w-[3.23rem]"></div>
     <div class="max-w-[calc(100%+1rem)]"></div>
     <div class="max-w-[var(--width)]"></div>
-    <div class="h-[3.23rem]"></div>
-    <div class="h-[calc(100%+1rem)]"></div>
-    <div class="h-[var(--height)]"></div>
-    <div class="min-h-[3.23rem]"></div>
-    <div class="min-h-[calc(100%+1rem)]"></div>
-    <div class="min-h-[var(--height)]"></div>
-    <div class="max-h-[3.23rem]"></div>
-    <div class="max-h-[calc(100%+1rem)]"></div>
-    <div class="max-h-[var(--height)]"></div>
-    <div class="space-x-[20cm]"></div>
-    <div class="space-x-[calc(20%-1cm)]"></div>
-    <div class="columns-[20] columns-[var(--columns)]"></div>
-    <div class="grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
-    <div class="lg:grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
-    <div class="grid-rows-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
-    <div class="col-[7]"></div>
-    <div class="col-end-[7]"></div>
-    <div class="col-start-[7]"></div>
+
     <div class="flex-[var(--flex)]"></div>
-    <div class="flex-grow-[var(--grow)]"></div>
     <div class="flex-shrink-[var(--shrink)]"></div>
-    <div class="row-[7]"></div>
-    <div class="row-end-[7]"></div>
-    <div class="row-start-[7]"></div>
+    <div class="flex-grow-[var(--grow)]"></div>
+
+    <div class="origin-[50px_50px]"></div>
+
+    <div class="translate-x-[12%]"></div>
+    <div class="translate-x-[var(--value)]"></div>
+    <div class="translate-y-[12%]"></div>
+    <div class="translate-y-[var(--value)]"></div>
+
     <div class="rotate-[23deg] rotate-[2.3rad] rotate-[401grad] rotate-[1.5turn]"></div>
+
     <div class="skew-x-[3px]"></div>
+    <div class="skew-x-[var(--value)]"></div>
     <div class="skew-y-[3px]"></div>
-    <div class="indent-[50%] indent-[var(--indent)]"></div>
-    <div class="align-[10em]"></div>
-    <div class="text-[2.23rem]"></div>
-    <div class="text-[length:var(--font-size)]"></div>
-    <div class="text-[color:var(--color)]"></div>
-    <div class="text-[angle:var(--angle)]"></div>
-    <div class="transition-[opacity,width]"></div>
-    <div class="duration-[2s]"></div>
-    <div class="m-[7px]"></div>
-    <div class="mx-[7px]"></div>
-    <div class="my-[7px]"></div>
-    <div class="mt-[7px]"></div>
-    <div class="mr-[7px]"></div>
-    <div class="mb-[7px]"></div>
-    <div class="ml-[7px]"></div>
-    <div class="mt-[clamp(30px,100px)]"></div>
+    <div class="skew-y-[var(--value)]"></div>
+
+    <div class="scale-[0.7]"></div>
+    <div class="scale-[var(--value)]"></div>
+    <div class="scale-x-[0.7]"></div>
+    <div class="scale-x-[var(--value)]"></div>
+    <div class="scale-y-[0.7]"></div>
+    <div class="scale-y-[var(--value)]"></div>
+
+    <div class="animate-[pong_1s_cubic-bezier(0,0,0.2,1)_infinite]"></div>
+    <div class="animate-[var(--value)]"></div>
+
+    <div class="cursor-[pointer]"></div>
+    <div class="cursor-[url(hand.cur)_2_2,pointer]"></div>
+    <div class="cursor-[var(--value)]"></div>
+
+    <div class="list-['\1F44D']"></div>
+    <div class="list-[var(--value)]"></div>
+
+    <div class="columns-[20] columns-[var(--columns)]"></div>
+
+    <div class="auto-cols-[minmax(10px,auto)]"></div>
+
+    <div class="auto-rows-[minmax(10px,auto)]"></div>
+
+    <div class="grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
+    <div class="lg:grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
+
+    <div class="grid-rows-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
+
+    <div class="gap-[20px]"></div>
+    <div class="gap-[var(--value)]"></div>
+    <div class="gap-x-[20px]"></div>
+    <div class="gap-x-[var(--value)]"></div>
+    <div class="gap-y-[20px]"></div>
+    <div class="gap-y-[var(--value)]"></div>
+
+    <div class="space-x-[20cm]"></div>
+    <div class="space-x-[calc(20%-1cm)]"></div>
+    <div class="space-y-[20cm]"></div>
+    <div class="space-y-[calc(20%-1cm)]"></div>
+
+    <div class="divide-x-[20cm]"></div>
+    <div class="divide-x-[calc(20%-1cm)]"></div>
+    <div class="divide-y-[20cm]"></div>
+    <div class="divide-y-[calc(20%-1cm)]"></div>
+
+    <div class="divide-[black]"></div>
+    <div class="divide-[var(--value)]"></div>
+
+    <div class="divide-opacity-[0.8]"></div>
+    <div class="divide-opacity-[var(--value)]"></div>
+
     <div class="rounded-[11px]"></div>
     <div
       class="
@@ -89,54 +161,185 @@
         rounded-tl-[var(--radius)]
       "
     ></div>
-    <div class="duration-[var(--app-duration)]"></div>
-    <div class="p-[var(--app-padding)]"></div>
-    <div class="inset-[11px]"></div>
-    <div class="blur-[15px]"></div>
-    <div class="brightness-[300%]"></div>
-    <div class="contrast-[2.4]"></div>
-    <div class="grayscale-[0.55]"></div>
-    <div class="hue-rotate-[0.8turn]"></div>
-    <div class="invert-[0.75]"></div>
-    <div class="saturate-[180%]"></div>
-    <div class="sepia-[0.2]"></div>
-    <div class="backdrop-blur-[11px]"></div>
-    <div class="backdrop-brightness-[1.23]"></div>
-    <div class="backdrop-contrast-[0.87]"></div>
-    <div class="backdrop-grayscale-[0.42]"></div>
-    <div class="backdrop-hue-rotate-[1.57rad]"></div>
-    <div class="backdrop-invert-[0.66]"></div>
-    <div class="backdrop-opacity-[22%]"></div>
-    <div class="backdrop-saturate-[144%]"></div>
-    <div class="backdrop-sepia-[0.38]"></div>
+
+    <div class="border-[#f00]"></div>
+    <div class="border-[red_black]"></div>
+    <div class="border-[2.5px]"></div>
+    <div class="border-[color:var(--value)]"></div>
+    <div class="border-[length:var(--value)]"></div>
+
+    <div class="border-t-[#f00]"></div>
+    <div class="border-t-[2.5px]"></div>
+    <div class="border-t-[color:var(--value)]"></div>
+    <div class="border-t-[length:var(--value)]"></div>
+    <div class="border-r-[#f00]"></div>
+    <div class="border-r-[2.5px]"></div>
+    <div class="border-r-[color:var(--value)]"></div>
+    <div class="border-r-[length:var(--value)]"></div>
+    <div class="border-b-[#f00]"></div>
+    <div class="border-b-[2.5px]"></div>
+    <div class="border-b-[color:var(--value)]"></div>
+    <div class="border-b-[length:var(--value)]"></div>
+    <div class="border-l-[#f00]"></div>
+    <div class="border-l-[2.5px]"></div>
+    <div class="border-l-[color:var(--value)]"></div>
+    <div class="border-l-[length:var(--value)]"></div>
+
+    <div class="border-opacity-[0.8]"></div>
+    <div class="border-opacity-[var(--value)]"></div>
+
+    <div class="bg-[#0f0] bg-[#ff0000] bg-[#0000ffcc]"></div>
+    <div class="bg-[rgb(123,123,123)] bg-[rgba(123,123,123,0.5)]"></div>
+    <div class="bg-[rgb(123,_456,_123)_black]"></div>
+    <div class="bg-[rgb(123_456_789)]"></div>
+    <div class="bg-[hsl(0,100%,50%)] bg-[hsla(0,100%,50%,0.3)]"></div>
+    <div class="bg-[#0f0_var(--value)]"></div>
+    <div class="bg-[var(--value1)_var(--value2)]"></div>
+    <div class="bg-[color:var(--value1)_var(--value2)]"></div>
+
+    <div class="bg-[url('/path-to-image.png')] bg-[url:var(--url)]"></div>
+    <div class="bg-[linear-gradient(#eee,#fff)]"></div>
+    <div class="bg-[linear-gradient(#eee,#fff),conic-gradient(red,orange,yellow,green,blue)]"></div>
+    <div class="bg-[image(),var(--value)]"></div>
+    <div class="bg-[var(--value),var(--value)]"></div>
+    <div class="bg-[image:var(--value),var(--value)]"></div>
+
+    <div class="bg-opacity-[0.11]"></div>
+    <div class="bg-opacity-[var(--value)]"></div>
+
     <div class="from-[#da5b66] via-[#da5b66] to-[#da5b66]"></div>
     <div class="from-[var(--color)] via-[var(--color)] to-[var(--color)]"></div>
+
+    <div class="bg-[length:200px_100px]"></div>
+    <div class="bg-[length:var(--value)]"></div>
+
+    <div class="bg-[position:200px_100px]"></div>
+    <div class="bg-[position:var(--value)]"></div>
+
     <div class="fill-[#da5b66]"></div>
-    <div class="fill-[var(--color)]"></div>
+    <div class="fill-[var(--value)]"></div>
+    <div class="fill-[url(#icon-gradient)]"></div>
+
+    <div class="stroke-[#da5b66]"></div>
+    <div class="stroke-[color:var(--value)]"></div>
+    <div class="stroke-[url(#icon-gradient)]"></div>
+
+    <div class="stroke-[20px]"></div>
+    <div class="stroke-[length:var(--value)]"></div>
+
     <div class="object-[50%,50%]"></div>
     <div class="object-[top,right]"></div>
     <div class="object-[var(--position)]"></div>
-    <div class="stroke-[#da5b66]"></div>
-    <div class="stroke-[url(#icon-gradient)]"></div>
+
+    <div class="p-[7px]"></div>
+    <div class="px-[7px]"></div>
+    <div class="py-[7px]"></div>
+    <div class="pt-[7px]"></div>
+    <div class="pr-[7px]"></div>
+    <div class="pb-[7px]"></div>
+    <div class="pl-[7px]"></div>
+    <div class="pt-[clamp(30px,100px)]"></div>
+
+    <div class="indent-[50%] indent-[var(--indent)]"></div>
+
+    <div class="align-[10em]"></div>
+
+    <div class="font-[Georgia,serif]"></div>
+    <div class="font-['Gill_Sans']"></div>
+    <div class="font-[sans-serif,serif]"></div>
+    <div class="font-[family-name:var(--value)]"></div>
+    <div class="font-[serif,var(--value)]"></div>
+    <div class="font-['Some_Font',sans-serif]"></div>
+    <div class="font-['Some_Font','Some_Other_Font']"></div>
+    <div class="font-['Some_Font',var(--other-font)]"></div>
+    <div class="font-[var(--font1),var(--font2)]"></div>
+    <div class="font-[invalid_font_because_spaces]"></div>
+
+    <div class="text-[2.23rem]"></div>
+    <div class="text-[length:var(--font-size)]"></div>
+    <div class="text-[angle:var(--angle)]"></div>
+
+    <div class="font-[300]"></div>
+    <div class="font-[number:lighter]"></div>
+    <div class="font-[number:var(--value)]"></div>
+
     <div class="leading-[var(--leading)]"></div>
+
     <div class="tracking-[var(--tracking)]"></div>
+
+    <div class="text-[black]"></div>
+    <div class="text-[rgb(123,123,123)]"></div>
+    <div class="text-[rgb(123,_123,_123)]"></div>
+    <div class="text-[rgb(123_123_123)]"></div>
+    <div class="text-[color:var(--color)]"></div>
+
+    <div class="text-opacity-[0.8]"></div>
+    <div class="text-opacity-[var(--value)]"></div>
+
     <div class="placeholder-[var(--placeholder)]"></div>
+
     <div class="placeholder-opacity-[var(--placeholder-opacity)]"></div>
+
+    <div class="caret-[black]"></div>
+    <div class="caret-[var(--value)]"></div>
+
+    <div class="accent-[#bada55]"></div>
+    <div class="accent-[var(--accent-color)]"></div>
+
+    <div class="opacity-[0.8]"></div>
     <div class="opacity-[var(--opacity)]"></div>
+
+    <div class="shadow-[0px_1px_2px_black]"></div>
+    <div class="shadow-[var(--value)]"></div>
+
+    <div class="outline-[2px_solid_black]"></div>
+    <div class="outline-[2px_solid_black,2px]"></div>
     <div class="outline-[var(--outline)]"></div>
+    <div class="outline-[var(--outline),3px]"></div>
+    <div class="outline-[2px_solid_black,var(--outline-offset)]"></div>
+
     <div class="ring-[#76ad65]"></div>
+    <div class="ring-[color:var(--value)]"></div>
     <div class="ring-offset-[#76ad65]"></div>
     <div class="ring-[10px]"></div>
+    <div class="ring-[length:(var(--value))]"></div>
     <div class="ring-offset-[#ad672f]"></div>
+    <div class="ring-offset-[color:var(--value)]"></div>
     <div class="ring-offset-[19rem]"></div>
+    <div class="ring-offset-[length:var(--value)]"></div>
     <div class="ring-opacity-[var(--ring-opacity)]"></div>
+
+    <div class="blur-[15px]"></div>
+    <div class="brightness-[300%]"></div>
+    <div class="contrast-[2.4]"></div>
+    <div class="drop-shadow-[0px_1px_2px_black]"></div>
+    <div class="grayscale-[0.55]"></div>
+    <div class="hue-rotate-[0.8turn]"></div>
+    <div class="invert-[0.75]"></div>
+    <div class="saturate-[180%]"></div>
+    <div class="sepia-[0.2]"></div>
+    <div class="backdrop-blur-[11px]"></div>
+    <div class="backdrop-brightness-[1.23]"></div>
+    <div class="backdrop-contrast-[0.87]"></div>
+    <div class="backdrop-grayscale-[0.42]"></div>
+    <div class="backdrop-hue-rotate-[1.57rad]"></div>
+    <div class="backdrop-invert-[0.66]"></div>
+    <div class="backdrop-opacity-[22%]"></div>
+    <div class="backdrop-saturate-[144%]"></div>
+    <div class="backdrop-sepia-[0.38]"></div>
+
+    <div class="transition-[opacity,width]"></div>
+
     <div class="delay-[var(--delay)]"></div>
+
+    <div class="duration-[2s]"></div>
+    <div class="duration-[var(--app-duration)]"></div>
+
     <div class="will-change-[top,left] will-change-[var(--will-change)]"></div>
+
     <div class="content-['hello']"></div>
     <div class="content-[attr(content-before)]"></div>
     <div class="content-['>']"></div>
-    <div class="accent-[#bada55]"></div>
-    <div class="accent-[var(--accent-color)]"></div>
 
     <!-- Balancing issues, this is not checking the validity of the actual value, but purely syntax-wise -->
     <div class="w-[do-not-generate-this]w-[it-is-invalid-syntax]"></div>
diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js
index 17252be9..f264faa0 100644
--- a/tests/arbitrary-values.test.js
+++ b/tests/arbitrary-values.test.js
@@ -16,6 +16,58 @@ test('arbitrary values', () => {
   })
 })
 
+it('should support arbitrary values for various background utilities', () => {
+  let config = {
+    content: [
+      {
+        raw: html`
+          <!-- Lookup -->
+          <div class="bg-gradient-to-r"></div>
+          <div class="bg-red-500"></div>
+
+          <!-- By implicit type -->
+          <div class="bg-[url('/image-1-0.png')]"></div>
+          <div class="bg-[#ff0000]"></div>
+
+          <!-- By explicit type -->
+          <div class="bg-[url:var(--image-url)]"></div>
+          <div class="bg-[color:var(--bg-color)]"></div>
+        `,
+      },
+    ],
+  }
+
+  return run('@tailwind utilities', config).then((result) => {
+    return expect(result.css).toMatchFormattedCss(css`
+      .bg-red-500 {
+        --tw-bg-opacity: 1;
+        background-color: rgb(239 68 68 / var(--tw-bg-opacity));
+      }
+
+      .bg-\\[\\#ff0000\\] {
+        --tw-bg-opacity: 1;
+        background-color: rgb(255 0 0 / var(--tw-bg-opacity));
+      }
+
+      .bg-\\[color\\:var\\(--bg-color\\)\\] {
+        background-color: var(--bg-color);
+      }
+
+      .bg-gradient-to-r {
+        background-image: linear-gradient(to right, var(--tw-gradient-stops));
+      }
+
+      .bg-\\[url\\(\\'\\/image-1-0\\.png\\'\\)\\] {
+        background-image: url('/image-1-0.png');
+      }
+
+      .bg-\\[url\\:var\\(--image-url\\)\\] {
+        background-image: var(--image-url);
+      }
+    `)
+  })
+})
+
 it('should not generate any css if an unknown typehint is used', () => {
   let config = {
     content: [
@@ -59,6 +111,8 @@ it('should convert _ to spaces', () => {
           <div class="auto-cols-[minmax(0,_1fr)]"></div>
           <div class="drop-shadow-[0px_1px_3px_black]"></div>
           <div class="content-[_hello_world_]"></div>
+          <div class="content-[___abc____]"></div>
+          <div class="content-['__hello__world__']"></div>
         `,
       },
     ],
@@ -113,9 +167,18 @@ it('should convert _ to spaces', () => {
         --tw-drop-shadow: drop-shadow(0px 1px 3px black);
         filter: var(--tw-filter);
       }
+
       .content-\\[_hello_world_\\] {
         content: hello world;
       }
+
+      .content-\\[___abc____\\] {
+        content: abc;
+      }
+
+      .content-\\[\\'__hello__world__\\'\\] {
+        content: '  hello  world  ';
+      }
     `)
   })
 })