DEV Community

Cover image for How I Finally Made TailwindCSS Work Inside the Shadow DOM (A Real Case Study)
Dhiraj Arya
Dhiraj Arya

Posted on

How I Finally Made TailwindCSS Work Inside the Shadow DOM (A Real Case Study)

When I started building a Chrome extension using the WXT extension framework and displaying UI components, everything looked great on the demo site, and Tailwind CSS was working perfectly.

But the moment I injected my UI into website on LinkedIn...

BOOM—my entire styling look ugly and small hole UI.

Button lost their padding, text lost font family, margin reset etc.

At first, I Thought---

"This must be a path issue... maybe css not import on react index file."

But the actual reason was something deeper-


When you build UI components in the Shadow DOM feels like a perfect solution:

✅ No CSS conflicts
✅ Clean encapsulation
✅ Consistent rendering on any website

At least, that’s what I expected.

This blog is a case study of the exact problem I faced, how I solved it, and what you should do if you face the same!

But instead, I hit a strange styling bug:
some TailwindCSS utilities worked fine — while others looked broken, tiny, misaligned, or squashed.

It took real debugging to discover the actual culprit:
Tailwind’s default sizing units (rem) behave differently inside injected Shadow DOM contexts.
Switching to px fixed everything immediately.

This case study breaks down what happened and how to fix it professionally.


🧩 The Symptom

I injected a React/Tailwind UI into LinkedIn using content script:

<Button onClick={action}  disabled={Boolean(loading)}>
          {loading ? 
            <> <Loader2 className="animate-spin size-6 mr-1" /> Analyzing </> : 
            <><Search className="size-5 mr-1" /> Analyze </> }
</Button>
Enter fullscreen mode Exit fullscreen mode

Inside my demo site, it looked perfect because it self build on tailwind css.

But when injected into LinkedIn using Shadow DOM:

  • Padding looked way smaller
  • Font size looked inconsistent
  • Border radius felt reduced
  • Layout spacing collapsed

I thought:

“Did Tailwind fail inside Shadow Root again?, reload my extension.”

But my styles were properly injected into the HTML style tag when checking using the inspect element.


🔍 First Debugging Try

I inspected the computed styles.

Tailwind style by default:

  • p-30.75rem
  • text-sm0.875rem
  • rounded-lg0.5rem

I read the official documentation, which explains that the rem value is used by default and refers to the rem of the parent. Therefore, the value depends entirely on the root element font-size.

And guess what?

The Shadow DOM inherits Linkedin html reference:

html {
  font-size: 10px;
}
Enter fullscreen mode Exit fullscreen mode

from the host page.

LinkedIn overrides it globally.

So:

1rem ≠ 16px anymore
Enter fullscreen mode Exit fullscreen mode

It can become:

  • 12px
  • 14px
  • or sometimes less, depending on the site component

That’s why everything looked shrunk.

Mystery solved.


🧠 Why REM is Breaking Here

REM values are relative to:

html {
  font-size: ?
}
Enter fullscreen mode Exit fullscreen mode

Within the Shadow DOM, font size can be inherited from the parent DOM. Some websites set font sizes aggressively, and accessibility settings can also influence it.

So Tailwind utilities change visually depending on the website’s design.

On LinkedIn, indeed:

  • They apply small base font sizes internally
  • So your component shrinks too

💡 The Simple Fix That Worked: Switch REM → PX

By disabling Tailwind’s default REM behavior, and using px for spacing & fonts, everything instantly became:

✅ Consistent
✅ Predictable
✅ Website-independent

No more random shrinkage.


✅ How to Switch Tailwind to PX (Production-Ready)

Update your tailwind.config.js if you are using Tailwind CSS v3:

export default {
  content: ["entrypoints/**/*.jsx", "components/**/*.jsx"],
  theme: {
    fontSize: {
      'xs': '12px',
      'sm': '14px',
      'base': '16px',
      'lg': '18px',
      'xl': '20px',
      '2xl': '24px',
      '3xl': '30px',
      '4xl': '36px',
      '5xl': '48px',
      '6xl': '60px',
      '7xl': '72px',
    },
    spacing: {
      px: '1px',
      0: '0',
      0.5: '2px',
      1: '4px',
      1.5: '6px',
      2: '8px',
      2.5: '10px',
      3: '12px',
      3.5: '14px',
      4: '16px',
      5: '20px',
      6: '24px',
      7: '28px',
      8: '32px',
      9: '36px',
      10: '40px',
      11: '44px',
      12: '48px',
      14: '56px',
      16: '64px',
      20: '80px',
      24: '96px',
      28: '112px',
      32: '128px',
      36: '144px',
      40: '160px',
      44: '176px',
      48: '192px',
      52: '208px',
      56: '224px',
      60: '240px',
      64: '256px',
      72: '288px',
      80: '320px',
      96: '384px',
    },
    extend: {
      lineHeight: {
        3: '12px',
        4: '16px',
        5: '20px',
        6: '24px',
        7: '28px',
        8: '32px',
        9: '36px',
        10: '40px',
      },
    },
  },
}

Enter fullscreen mode Exit fullscreen mode

Update your tailwind.css & main.css if you are using Tailwind CSS v4:

@theme inline {
 /* Font Sizes */
  --text-xs: 12px;
  --text-sm: 14px;
  --text-base: 16px;
  --text-lg: 18px;
  --text-xl: 20px;
  --text-2xl: 24px;
  --text-3xl: 30px;
  --text-4xl: 36px;
  --text-5xl: 48px;
  --text-6xl: 60px;
  --text-7xl: 72px;

  /* Line Heights */
  --leading-3: 12px;
  --leading-4: 16px;
  --leading-5: 20px;
  --leading-6: 24px;
  --leading-7: 28px;
  --leading-8: 32px;
  --leading-9: 36px;
  --leading-10: 40px;

  /* Radius */
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  /* Spacing */
  --spacing-px: 1px;
  --spacing-0: 0;
  --spacing-0\.5: 2px;
  --spacing-1: 4px;
  --spacing-1\.5: 6px;
  --spacing-2: 8px;
  --spacing-2\.5: 10px;
  --spacing-3: 12px;
  --spacing-3\.5: 14px;
  --spacing-4: 16px;
  --spacing-5: 20px;
  --spacing-6: 24px;
  --spacing-7: 28px;
  --spacing-8: 32px;
  --spacing-9: 36px;
  --spacing-10: 40px;
  --spacing-11: 44px;
  --spacing-12: 48px;
  --spacing-14: 56px;
  --spacing-16: 64px;
  --spacing-20: 80px;
  --spacing-24: 96px;
  --spacing-28: 112px;
  --spacing-32: 128px;
  --spacing-36: 144px;
  --spacing-40: 160px;
  --spacing-44: 176px;
  --spacing-48: 192px;
  --spacing-52: 208px;
  --spacing-56: 224px;
  --spacing-60: 240px;
  --spacing-64: 256px;
  --spacing-72: 288px;
  --spacing-80: 320px;
  --spacing-96: 384px;
}

Enter fullscreen mode Exit fullscreen mode

Now Tailwind generates pixel-based utilities instead of rem units.


After Tailwind change to Px when my Extalent UI

✅ Even Faster Option: Use Tailwind's built-in px sizing(Not Recommended)

Tailwind already supports px helpers:

<p class="text-[16px] p-[12px] rounded-[8px]">
  Shadow DOM safe styling!
</p>
Enter fullscreen mode Exit fullscreen mode

These never scale with rem.


✅ Another Production Pattern (Highly Recommended)

Declare a stable base inside Shadow DOM:

shadowRoot.innerHTML = `
  <style>
    :host, * {
      font-size: 16px;
    }
  </style>
`
Enter fullscreen mode Exit fullscreen mode

Now 1rem = 16px everywhere.
No host page influence.


🚫 Why You Shouldn’t Ignore This

Without this fix, your UI might:

❌ look good on localhost
❌ break on LinkedIn
❌ shrink on Indeed
❌ compress on Medium
❌ stretch on platforms with accessibility scaling

Consistency is everything for product UX.


🔥 Conclusion

Tailwind CSS is extremely powerful, but when working with Shadow DOM or injected UIs, it's important to manage sizing effectively.

I learned:

  • rem is influenced by host page
  • Shadow DOM inherits font-size by default
  • Website overrides can shrink your component
  • Pixel units remove unpredictability

Switching Tailwind utilities to px gave me:

✅ Consistent UI everywhere
✅ Perfect spacing
✅ Fixed text scaling
✅ Professional look

Now my Chrome extension UI looks identical on LinkedIn website.


🧠 Real-World Takeaway

If you’re building:

  • Browser extensions
  • Job assistant UIs
  • Embeddable SaaS widgets
  • Micro frontends
  • Marketing overlays

Avoid rem unless you reset base font-size manually.


Happy shipping! 🚀

Top comments (0)