diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js
index 44e4a22f..653d5a9b 100644
--- a/src/components/shadow_control/shadow_control.js
+++ b/src/components/shadow_control/shadow_control.js
@@ -61,6 +61,21 @@ export default {
         }
       }
     },
+    currentFallback () {
+      if (this.ready && this.fallback.length > 0) {
+        return this.fallback[this.selectedId]
+      } else {
+        return {
+          x: 0,
+          y: 0,
+          blur: 0,
+          spread: 0,
+          inset: false,
+          color: '#000000',
+          alpha: 1
+        }
+      }
+    },
     moveUpValid () {
       return this.ready && this.selectedId > 0
     },
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index de8a42d1..efbb980e 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -191,6 +191,8 @@
         v-model="selected.color"
         :disabled="!present"
         :label="$t('settings.style.common.color')"
+        :fallback="currentFallback.color"
+        :showOptionalTickbox="false"
         name="shadow"
       />
       <OpacityInput
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 52ece3a1..2984873f 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -5,6 +5,7 @@ import {
   getContrastRatioLayers
 } from '../../services/color_convert/color_convert.js'
 import {
+  DEFAULT_SHADOWS,
   generateColors,
   generateShadows,
   generateRadii,
@@ -76,7 +77,7 @@ export default {
         .reduce((acc, [key, val]) => ({ ...acc, [ key + 'ColorLocal' ]: val }), {}),
 
       ...Object.keys(OPACITIES)
-        .map(key => console.log(key) || [key, ''])
+        .map(key => [key, ''])
         .reduce((acc, [key, val]) => ({ ...acc, [ key + 'OpacityLocal' ]: val }), {}),
 
       shadowSelected: undefined,
@@ -134,7 +135,7 @@ export default {
     },
     currentOpacity () {
       return Object.keys(OPACITIES)
-        .map(key => console.log(key) || [key, this[key + 'OpacityLocal']])
+        .map(key => [key, this[key + 'OpacityLocal']])
         .reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
     },
     currentRadii () {
@@ -224,7 +225,7 @@ export default {
       ].join(';')
     },
     shadowsAvailable () {
-      return Object.keys(this.previewTheme.shadows).sort()
+      return Object.keys(DEFAULT_SHADOWS).sort()
     },
     currentShadowOverriden: {
       get () {
@@ -239,7 +240,7 @@ export default {
       }
     },
     currentShadowFallback () {
-      return this.previewTheme.shadows[this.shadowSelected]
+      return (this.previewTheme.shadows || {})[this.shadowSelected]
     },
     currentShadow: {
       get () {
@@ -314,6 +315,17 @@ export default {
         }
       })
     },
+    updatePreviewColorsAndShadows () {
+      this.previewColors = generateColors({
+        opacity: this.currentOpacity,
+        colors: this.currentColors
+      })
+      this.previewShadows = generateShadows(
+        { shadows: this.shadowsLocal },
+        this.previewColors.theme.colors,
+        this.previewColors.mod
+      )
+    },
     onImport (parsed) {
       if (parsed._pleroma_theme_version === 1) {
         this.normalizeLocalState(parsed, 1)
@@ -435,6 +447,14 @@ export default {
         })
       }
 
+      if (opacity && !this.keepOpacity) {
+        this.clearOpacity()
+        Object.entries(opacity).forEach(([k, v]) => {
+          if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
+          this[k + 'OpacityLocal'] = v
+        })
+      }
+
       if (!this.keepRoundness) {
         this.clearRoundness()
         Object.entries(radii).forEach(([k, v]) => {
@@ -454,14 +474,6 @@ export default {
         this.clearFonts()
         this.fontsLocal = fonts
       }
-
-      if (opacity && !this.keepOpacity) {
-        this.clearOpacity()
-        Object.entries(opacity).forEach(([k, v]) => {
-          if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
-          this[k + 'OpacityLocal'] = v
-        })
-      }
     }
   },
   watch: {
@@ -476,8 +488,9 @@ export default {
     },
     shadowsLocal: {
       handler () {
+        if (Object.getOwnPropertyNames(this.previewColors).length === 1) return
         try {
-          this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
+          this.updatePreviewColorsAndShadows()
           this.shadowsInvalid = false
         } catch (e) {
           this.shadowsInvalid = true
@@ -500,10 +513,7 @@ export default {
     },
     currentColors () {
       try {
-        this.previewColors = generateColors({
-          opacity: this.currentOpacity,
-          colors: this.currentColors
-        })
+        this.updatePreviewColorsAndShadows()
         this.colorsInvalid = false
       } catch (e) {
         this.colorsInvalid = true
@@ -512,10 +522,7 @@ export default {
     },
     currentOpacity () {
       try {
-        this.previewColors = generateColors({
-          opacity: this.currentOpacity,
-          colors: this.currentColors
-        })
+        this.updatePreviewColorsAndShadows()
       } catch (e) {
         console.warn(e)
       }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index c8c02b8d..287d31b7 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -691,7 +691,7 @@
               {{ $t('settings.style.switcher.clear_all') }}
             </button>
           </div>
-          <shadow-control
+          <ShadowControl
             v-model="currentShadow"
             :ready="!!currentShadowFallback"
             :fallback="currentShadowFallback"
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 872dd393..74af190c 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,7 +1,7 @@
 import { times } from 'lodash'
 import { convert } from 'chromatism'
 import { rgb2hex, hex2rgb, rgba2css, getCssColor } from '../color_convert/color_convert.js'
-import { getColors } from '../theme_data/theme_data.service.js'
+import { getColors, computeDynamicColor } from '../theme_data/theme_data.service.js'
 
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
@@ -139,7 +139,8 @@ export const generateColors = (themeData) => {
     theme: {
       colors: htmlColors.solid,
       opacity
-    }
+    },
+    mod
   }
 }
 
@@ -211,83 +212,99 @@ export const generateFonts = (input) => {
   }
 }
 
-export const generateShadows = (input) => {
-  const border = (top, shadow) => ({
-    x: 0,
-    y: top ? 1 : -1,
-    blur: 0,
+const border = (top, shadow) => ({
+  x: 0,
+  y: top ? 1 : -1,
+  blur: 0,
+  spread: 0,
+  color: shadow ? '#000000' : '#FFFFFF',
+  alpha: 0.2,
+  inset: true
+})
+const buttonInsetFakeBorders = [border(true, false), border(false, true)]
+const inputInsetFakeBorders = [border(true, true), border(false, false)]
+const hoverGlow = {
+  x: 0,
+  y: 0,
+  blur: 4,
+  spread: 0,
+  color: '--faint',
+  alpha: 1
+}
+
+export const DEFAULT_SHADOWS = {
+  panel: [{
+    x: 1,
+    y: 1,
+    blur: 4,
     spread: 0,
-    color: shadow ? '#000000' : '#FFFFFF',
-    alpha: 0.2,
-    inset: true
-  })
-  const buttonInsetFakeBorders = [border(true, false), border(false, true)]
-  const inputInsetFakeBorders = [border(true, true), border(false, false)]
-  const hoverGlow = {
+    color: '#000000',
+    alpha: 0.6
+  }],
+  topBar: [{
     x: 0,
     y: 0,
     blur: 4,
     spread: 0,
-    color: '--faint',
+    color: '#000000',
+    alpha: 0.6
+  }],
+  popup: [{
+    x: 2,
+    y: 2,
+    blur: 3,
+    spread: 0,
+    color: '#000000',
+    alpha: 0.5
+  }],
+  avatar: [{
+    x: 0,
+    y: 1,
+    blur: 8,
+    spread: 0,
+    color: '#000000',
+    alpha: 0.7
+  }],
+  avatarStatus: [],
+  panelHeader: [],
+  button: [{
+    x: 0,
+    y: 0,
+    blur: 2,
+    spread: 0,
+    color: '#000000',
     alpha: 1
-  }
-
-  const shadows = {
-    panel: [{
-      x: 1,
-      y: 1,
-      blur: 4,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.6
-    }],
-    topBar: [{
-      x: 0,
-      y: 0,
-      blur: 4,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.6
-    }],
-    popup: [{
-      x: 2,
-      y: 2,
-      blur: 3,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.5
-    }],
-    avatar: [{
-      x: 0,
-      y: 1,
-      blur: 8,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.7
-    }],
-    avatarStatus: [],
-    panelHeader: [],
-    button: [{
-      x: 0,
-      y: 0,
-      blur: 2,
-      spread: 0,
-      color: '#000000',
-      alpha: 1
-    }, ...buttonInsetFakeBorders],
-    buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
-    buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
-    input: [...inputInsetFakeBorders, {
-      x: 0,
-      y: 0,
-      blur: 2,
-      inset: true,
-      spread: 0,
-      color: '#000000',
-      alpha: 1
-    }],
+  }, ...buttonInsetFakeBorders],
+  buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
+  buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
+  input: [...inputInsetFakeBorders, {
+    x: 0,
+    y: 0,
+    blur: 2,
+    inset: true,
+    spread: 0,
+    color: '#000000',
+    alpha: 1
+  }]
+}
+export const generateShadows = (input, colors, mod) => {
+  const shadows = Object.entries({
+    ...DEFAULT_SHADOWS,
     ...(input.shadows || {})
-  }
+  }).reduce((shadowsAcc, [slotName, shadowdefs]) => {
+    const newShadow = shadowdefs.reduce((shadowAcc, def) => [
+      ...shadowAcc,
+      {
+        ...def,
+        color: rgb2hex(computeDynamicColor(
+          def.color,
+          (variableSlot) => convert(colors[variableSlot]).rgb,
+          mod
+        ))
+      }
+    ], [])
+    return { ...shadowsAcc, [slotName]: newShadow }
+  }, {})
 
   return {
     rules: {
@@ -325,12 +342,15 @@ export const composePreset = (colors, radii, shadows, fonts) => {
   }
 }
 
-export const generatePreset = (input) => composePreset(
-  generateColors(input),
-  generateRadii(input),
-  generateShadows(input),
-  generateFonts(input)
-)
+export const generatePreset = (input) => {
+  const colors = generateColors(input)
+  return composePreset(
+    colors,
+    generateRadii(input),
+    generateShadows(input, colors.theme.colors, colors.mod),
+    generateFonts(input)
+  )
+}
 
 export const getThemes = () => {
   return window.fetch('/static/styles.json')
@@ -362,7 +382,7 @@ export const getThemes = () => {
 
 export const setPreset = (val, commit) => {
   return getThemes()
-    .then((themes) => console.log(themes) || themes[val] ? themes[val] : themes['pleroma-dark'])
+    .then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
     .then((theme) => {
       const isV1 = Array.isArray(theme)
       const data = isV1 ? {} : theme.theme
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 9f010fdf..e4456b29 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -697,6 +697,22 @@ export const OPACITIES = Object.entries(SLOT_INHERITANCE).reduce((acc, [k, v]) =
   }
 }, {})
 
+/**
+ * Handle dynamic color
+ */
+export const computeDynamicColor = (sourceColor, getColor, mod) => {
+  if (typeof sourceColor !== 'string' || !sourceColor.startsWith('--')) return sourceColor
+  let targetColor = null
+  // Color references other color
+  const [variable, modifier] = sourceColor.split(/,/g).map(str => str.trim())
+  const variableSlot = variable.substring(2)
+  targetColor = getColor(variableSlot)
+  if (modifier) {
+    targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
+  }
+  return targetColor
+}
+
 /**
  * THE function you want to use. Takes provided colors and opacities, mod
  * value and uses inheritance data to figure out color needed for the slot.
@@ -728,13 +744,11 @@ export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.redu
         a: 0
       }
     } else if (typeof sourceColor === 'string' && sourceColor.startsWith('--')) {
-      // Color references other color
-      const [variable, modifier] = sourceColor.split(/,/g).map(str => str.trim())
-      const variableSlot = variable.substring(2)
-      targetColor = colors[variableSlot] || sourceColors[variableSlot]
-      if (modifier) {
-        targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
-      }
+      targetColor = computeDynamicColor(
+        sourceColor,
+        variableSlot => colors[variableSlot] || sourceColors[variableSlot],
+        mod
+      )
     } else if (typeof sourceColor === 'string' && sourceColor.startsWith('#')) {
       targetColor = convert(targetColor).rgb
     }