Salesforce

Intro to CSS for LWC: Why Your Component Still Looks Broken

Your component works. The data loads, the click handlers fire, the logic is correct. And it still looks like a first draft — cramped spacing, misaligned text, no visual hierarchy. That's not a JavaScript problem. That's a CSS problem, and it's the one most Salesforce developers skip past instead of actually learning.

Why CSS Matters for LWC Styling

HTML gives your component structure — a div here, a button there, a list of records. CSS decides how that structure actually looks: spacing, color, alignment, size, layout. A component with flawless logic and zero CSS attention still reads as unfinished, because visual hierarchy is doing half the communication work whether you planned for it or not. Users trust a well-spaced, clearly aligned component more than a functionally identical one that looks cramped — that's not vanity, it's how people read interfaces.

Where CSS Actually Lives in an LWC

Every Lightning Web Component can have its own CSS file, sitting right alongside the JavaScript and HTML — myComponent.js, myComponent.html, myComponent.css, same folder, same base name. You don't import it and you don't link it in the HTML. The platform wires it up automatically the moment the file exists, and its styles apply only within that component's own template.

Basic CSS syntax, for anyone who needs the refresher: a selector, then curly braces, then one or more property-value pairs ending in semicolons.

.highlight {
  color: #c8401a;
  font-weight: 700;
}

Selectors and Specificity

Three selector types cover almost everything you'll write. Element selectors target a tag directly — a rule on button styles every button in the template. Class selectors, written with a leading dot, target anything carrying that class — reusable and specific, and the one you'll reach for most. ID selectors, written with a leading hash, target one exact element — rare in LWC, and generally avoided in favor of classes.

.card {
  padding: 16px;
  border-radius: 8px;
}

.card h2 {
  margin-bottom: 8px;
}

.card .highlight {
  color: #c8401a;
}

Specificity is the part that actually breaks people's styles. When two rules target the same element, the more specific selector wins — not whichever one was written last in the file. This is why a class rule can lose to an ID rule that appears earlier, and it's the single most common reason a CSS change "doesn't seem to do anything."

The specificity hierarchy, low to high: element selectors, then class selectors, then ID selectors, then inline styles, with !important overriding everything regardless of specificity. Avoid !important — it's a shortcut that makes future debugging considerably harder.
p { color: black; }         /* loses */
.note { color: blue; }      /* loses */
#summary { color: red; }    /* wins — ID beats class and element */

Flexbox Basics

Flexbox is the one layout tool that solves most layout problems you'll hit in component work. Set display: flex on a parent container, and every direct child inside it becomes a flex item that the parent can align, space, and reorder — no floats, no manual positioning.

.row {
  display: flex;
}

/* every direct child of .row now lines up
   horizontally, automatically */

Three properties you'll reach for constantly: justify-content controls horizontal spacing — space-between, center, flex-end. align-items controls vertical alignment within the row, and center is the one you'll use most. flex-direction flips the axis entirely — row by default, column when you want a vertical stack instead.

.field-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* label on the left, value on the right —
   no absolute positioning required */

SLDS Utility Classes vs Custom CSS

Salesforce ships the Salesforce Lightning Design System — SLDS — with hundreds of pre-built utility classes for spacing, grids, typography, and buttons. slds-m-around_medium adds margin. slds-grid turns on flex layout. slds-p-around_small adds padding. These exist so components across the entire platform look consistent without every developer reinventing the same rules.

<div class="slds-grid slds-wrap slds-p-around_medium">
  <div class="slds-col slds-size_1-of-2">Label</div>
  <div class="slds-col slds-size_1-of-2">Value</div>
</div>

<!-- zero custom CSS required for this layout -->

The practical rule: use SLDS first, always, for spacing, grids, standard buttons, and standard text styles. Write custom CSS only for what SLDS genuinely doesn't cover — a specific brand color, a custom animation, or a layout SLDS's grid system can't produce cleanly.

Scoped CSS in LWC: Shadow DOM Implications

Here's the part that's specific to LWC and trips up developers coming from plain web development. Every LWC template renders inside a shadow root, which means CSS written inside one component's file cannot style elements inside a child component — and CSS from outside the component cannot reach in either.

div {
  padding: 8px;
}
/* only touches <div> elements inside THIS
   component's own template — never inside
   a child component it renders */

:host {
  display: block;
}
/* :host styles the component's own root
   element from the inside */

A generic selector like div or p in your component's CSS only ever touches elements inside that specific component's own template. Use the :host selector when you need to style the component's own root element from inside its own stylesheet, since :host specifically targets the custom element boundary shadow DOM creates.

Common Layout Patterns for Lightning Components

A handful of patterns cover most of what you'll rebuild: a card — padding, border-radius, a subtle box-shadow. A two-column form row — flexbox with justify-content: space-between. A vertical listflex-direction: column with a border-bottom on each row instead of a full grid. Recognize these shapes and you'll write noticeably less CSS from scratch every time a new component needs one of them.

None of this requires mastering CSS as a discipline. It requires knowing where your styles live, why a rule sometimes loses to another rule, how flexbox actually lines things up, when to reach for SLDS instead of writing anything new, and what shadow DOM means for scoping. That's the whole intro — and it's the difference between a component that works and a component that looks finished.

← All articles

Frequently Asked Questions

Where does CSS live in a Lightning Web Component?

In its own file alongside the component's JavaScript and HTML — myComponent.css, myComponent.js, myComponent.html, all in the same folder with the same base name. You don't import or link the CSS file; the platform wires it up automatically as soon as the file exists.

Why does my CSS rule not apply even though the selector looks correct?

Almost always a specificity conflict. When two rules target the same element, the more specific selector wins regardless of which one appears later in the file — ID selectors beat class selectors, class selectors beat element selectors, and inline styles beat all of them. Check whether a more specific rule elsewhere is overriding the one you expect to apply.

Should I use SLDS utility classes or write custom CSS?

Use SLDS utility classes first for spacing, grids, standard buttons, and standard text styles — they're already built, tested, and consistent with the rest of the platform. Write custom CSS only for what SLDS genuinely doesn't cover, such as a specific brand color or a layout SLDS's grid system can't produce cleanly.

Can CSS from one Lightning Web Component affect another component?

No. LWC templates render inside a shadow root, so CSS written inside one component's file cannot style elements inside a child component, and CSS from outside the component cannot reach in either. Use the :host selector to style the component's own root element from inside its own stylesheet.