LWC uses Shadow DOM for encapsulation, but SLDS remains the recommended styling approach for clean Salesforce UI. Learn how to build polished, consistent component layouts.
Each LWC component has its own CSS file. Styles are automatically scoped to that component.
myComponent/
myComponent.html
myComponent.js
myComponent.css
/* myComponent.css */
.button-primary {
background-color: #0076d6;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.button-primary:hover {
background-color: #004a9e;
}
.card {
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
}
.card-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.card-body {
font-size: 14px;
color: #333;
}
<template>
<div class="card">
<h3 class="card-title">Account Details</h3>
<div class="card-body">
<p>Name: {account.Name}</p>
<p>Phone: {account.Phone}</p>
</div>
</div>
<button class="button-primary" onclick={handleClick}>
Save
</button>
</template>
CSS inside a component doesn't affect parent/sibling components, and vice versa.
/* Parent component CSS - doesn't affect child */
.card {
border: 3px solid red;
}
<template>
<c-child-component></c-child-component>
</template>
/* Child component CSS - stays scoped */
.card {
border: 1px solid blue; /* This takes precedence in child */
}
LWC integrates with SLDS for consistent Salesforce styling:
<template>
<div class="slds-box slds-var-m-around_medium">
<h2 class="slds-var-text-heading_large">Account</h2>
<div class="slds-form">
<div class="slds-form-element">
<label class="slds-form-element__label">Name</label>
<div class="slds-form-element__control">
<input type="text" class="slds-input" />
</div>
</div>
</div>
<button class="slds-button slds-button_brand">
Save
</button>
</div>
</template>
<template>
<button
class={buttonClass}
onclick={handleClick}>
Click me
</button>
</template>
// JavaScript
export default class ButtonComponent extends LightningElement {
isActive = false;
get buttonClass() {
return this.isActive ? 'slds-button slds-button_brand' : 'slds-button';
}
handleClick() {
this.isActive = !this.isActive;
}
}
<template>
<div style={boxStyle}>
Dynamic styled content
</div>
</template>
export default class DynamicStyleComponent extends LightningElement {
backgroundColor = '#f5f5f5';
padding = '20px';
get boxStyle() {
return `background-color: ${this.backgroundColor}; padding: ${this.padding};`;
}
}
Use CSS custom properties to allow parents to style children:
/* childComponent.css */
.container {
background-color: var(--container-bg, white);
color: var(--container-color, black);
padding: var(--container-padding, 10px);
}
/* parentComponent.css */
c-child-component {
--container-bg: #e8f4f8;
--container-color: #003366;
--container-padding: 20px;
}
/* Good - use SLDS spacing */
.card {
padding: var(--lwc-spacing_medium); /* 1rem */
margin-bottom: var(--lwc-spacing_large); /* 1.5rem */
}
.title {
font-size: var(--lwc-fontSize_heading_large);
color: var(--lwc-colorTextDefault);
}
/* ❌ Don't try to style child components from parent */
.child-component .card {
/* This won't work due to Shadow DOM */
}
/* ✅ Pass CSS variables instead */
.parent {
--card-border: 2px solid red;
}
/* In child component CSS */
.card {
border: var(--card-border, 1px solid gray);
}
/* Component CSS */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.card {
padding: 20px;
border: 1px solid #e0e0e0;
}
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
}
.card {
padding: 15px;
}
}
.container {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}
.sidebar {
flex: 0 0 250px; /* Fixed width */
}
.content {
flex: 1; /* Take remaining space */
}
.form {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.form-row {
grid-column: span 2; /* Full width */
}
@media (max-width: 768px) {
.form {
grid-template-columns: 1fr;
}
.form-row {
grid-column: span 1;
}
}