Skip to content
SalesforceSkills

Styling & CSS

Ready-made styles for cards, badges, tables, forms, and more. Like a recipe book for making things look good.

Skill Details

Install this skill

Versionv1.0.0AuthorBrendan SheridanLicenseMITSections9

Works with

Claude CodeCursorWindsurf

Bring Tailwind CSS methodology and Shadcn-inspired component design to Lightning Web Components using only SLDS 2 global styling hooks. Zero external dependencies — every pattern maps to --slds-g- custom properties.

Philosophy

1
Utility-first, SLDS-native — predefined CSS classes that map to SLDS hooks, not raw values
2
Scoped by design — LWC shadow DOM means utility classes are per-component, no global leaking
3
Composable — combine utility classes in HTML; override nothing
4
Zero dependencies — no Tailwind build step, no static resources, works in any Salesforce org

SLDS-to-Tailwind Mapping

Colors

Spacing

Typography

Border Radius

Shadows

Reusable Utility Classes

Include these in any LWC component's CSS file. Each class maps directly to SLDS 2 hooks.

Layout Utilities

CSS
/* Flex containers */
.util-stack {
    display: flex;
    flex-direction: column;
    gap: var(--slds-g-spacing-4, 1rem);
}

.util-stack--tight { gap: var(--slds-g-spacing-2, 0.5rem); }
.util-stack--loose { gap: var(--slds-g-spacing-6, 1.5rem); }

.util-cluster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--slds-g-spacing-3, 0.75rem);
    align-items: center;
}

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

.util-center {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Grid */
.util-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--slds-g-spacing-4, 1rem);
}

.util-grid--2col { grid-template-columns: repeat(2, 1fr); }
.util-grid--3col { grid-template-columns: repeat(3, 1fr); }
.util-grid--4col { grid-template-columns: repeat(4, 1fr); }

Surface Utilities

CSS
.util-surface {
    background: var(--slds-g-color-surface-1, #ffffff);
    color: var(--slds-g-color-on-surface-1, #181818);
}

.util-surface--muted {
    background: var(--slds-g-color-surface-container-1, #f8f8f8);
    color: var(--slds-g-color-on-surface-1, #181818);
}

.util-surface--raised {
    background: var(--slds-g-color-surface-1, #ffffff);
    box-shadow: var(--slds-g-shadow-2);
}

.util-surface--sunken {
    background: var(--slds-g-color-surface-container-2, #f3f3f3);
}

Text Utilities

CSS
.util-text--heading {
    font-size: var(--slds-g-font-size-7, 1.25rem);
    font-weight: var(--slds-g-font-weight-7, 700);
    color: var(--slds-g-color-on-surface-1, #181818);
    line-height: var(--slds-g-line-height-2, 1.25);
}

.util-text--subheading {
    font-size: var(--slds-g-font-size-4, 0.875rem);
    font-weight: var(--slds-g-font-weight-6, 600);
    color: var(--slds-g-color-on-surface-1, #181818);
}

.util-text--body {
    font-size: var(--slds-g-font-size-4, 0.875rem);
    color: var(--slds-g-color-on-surface-1, #181818);
    line-height: var(--slds-g-line-height-4, 1.5);
}

.util-text--caption {
    font-size: var(--slds-g-font-size-2, 0.75rem);
    color: var(--slds-g-color-on-surface-2, #444444);
}

.util-text--muted {
    color: var(--slds-g-color-on-surface-3, #706e6b);
}

.util-text--truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

Component Recipes

Card

Shadcn-inspired card with header, content, and footer slots.

HTML
<class="code-tag">template>
    <class="code-tag">div class={cardClass}>
        <class="code-tag">div class="recipe-card__header" if:true={title}>
            <class="code-tag">h3 class="recipe-card__title">{title}</class="code-tag">h3>
            <class="code-tag">div class="recipe-card__actions">
                <class="code-tag">slot name="actions"></class="code-tag">slot>
            </class="code-tag">div>
        </class="code-tag">div>
        <class="code-tag">div class="recipe-card__body">
            <class="code-tag">slot></class="code-tag">slot>
        </class="code-tag">div>
        <class="code-tag">div class="recipe-card__footer" if:true={hasFooter}>
            <class="code-tag">slot name="footer"></class="code-tag">slot>
        </class="code-tag">div>
    </class="code-tag">div>
</class="code-tag">template>
CSS
.recipe-card {
    background: var(--slds-g-color-surface-1, #ffffff);
    border: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-1, #e5e5e5);
    border-radius: var(--slds-g-radius-border-3, 0.5rem);
    overflow: hidden;
}

.recipe-card--elevated {
    box-shadow: var(--slds-g-shadow-2);
    border: none;
}

.recipe-card__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--slds-g-spacing-4, 1rem) var(--slds-g-spacing-4, 1rem) 0;
}

.recipe-card__title {
    font-size: var(--slds-g-font-size-5, 1rem);
    font-weight: var(--slds-g-font-weight-6, 600);
    color: var(--slds-g-color-on-surface-1, #181818);
    margin: 0;
}

.recipe-card__body {
    padding: var(--slds-g-spacing-4, 1rem);
}

.recipe-card__footer {
    padding: var(--slds-g-spacing-3, 0.75rem) var(--slds-g-spacing-4, 1rem);
    border-top: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-1, #e5e5e5);
    background: var(--slds-g-color-surface-container-1, #f8f8f8);
}

Badge / Pill

CSS
.recipe-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--slds-g-spacing-1, 0.25rem);
    padding: var(--slds-g-spacing-1, 0.25rem) var(--slds-g-spacing-3, 0.75rem);
    font-size: var(--slds-g-font-size-2, 0.75rem);
    font-weight: var(--slds-g-font-weight-5, 500);
    border-radius: var(--slds-g-radius-border-pill, 9999px);
    white-space: nowrap;
}

.recipe-badge--default {
    background: var(--slds-g-color-surface-container-2, #f3f3f3);
    color: var(--slds-g-color-on-surface-1, #181818);
}

.recipe-badge--success {
    background: var(--slds-g-color-success-container-1, #e6f9e6);
    color: var(--slds-g-color-success-1, #2e844a);
}

.recipe-badge--error {
    background: var(--slds-g-color-error-container-1, #fef1f1);
    color: var(--slds-g-color-error-1, #ea001e);
}

.recipe-badge--warning {
    background: var(--slds-g-color-warning-container-1, #fef4e6);
    color: var(--slds-g-color-warning-1, #dd7a01);
}

.recipe-badge--info {
    background: var(--slds-g-color-info-container-1, #e5f0fb);
    color: var(--slds-g-color-info-1, #0176d3);
}

Data Table with Hover

CSS
.recipe-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--slds-g-font-size-3, 0.8125rem);
}

.recipe-table th {
    text-align: left;
    padding: var(--slds-g-spacing-3, 0.75rem) var(--slds-g-spacing-4, 1rem);
    font-weight: var(--slds-g-font-weight-6, 600);
    color: var(--slds-g-color-on-surface-2, #444444);
    background: var(--slds-g-color-surface-container-1, #f8f8f8);
    border-bottom: var(--slds-g-sizing-border-2) solid var(--slds-g-color-border-1, #e5e5e5);
}

.recipe-table td {
    padding: var(--slds-g-spacing-3, 0.75rem) var(--slds-g-spacing-4, 1rem);
    color: var(--slds-g-color-on-surface-1, #181818);
    border-bottom: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-2, #eeeeee);
}

.recipe-table tr: hover td {
    background: var(--slds-g-color-surface-3, #f3f3f3);
}

.recipe-table tr: focus-within td {
    background: var(--slds-g-color-accent-container-1, #e5f0fb);
}

Form Input with Focus Ring

CSS
.recipe-input {
    width: 100%;
    padding: var(--slds-g-spacing-2, 0.5rem) var(--slds-g-spacing-3, 0.75rem);
    font-size: var(--slds-g-font-size-4, 0.875rem);
    color: var(--slds-g-color-on-surface-1, #181818);
    background: var(--slds-g-color-surface-1, #ffffff);
    border: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-1, #e5e5e5);
    border-radius: var(--slds-g-radius-border-2, 0.25rem);
    transition: border-color 150ms ease, box-shadow 150ms ease;
}

.recipe-input: hover {
    border-color: var(--slds-g-color-accent-2, #014486);
}

.recipe-input: focus {
    outline: none;
    border-color: var(--slds-g-color-accent-1, #0176d3);
    box-shadow: 0 0 0 3px var(--slds-g-color-accent-container-1, #e5f0fb);
}

.recipe-input: :placeholder {
    color: var(--slds-g-color-on-surface-3, #706e6b);
}

.recipe-input--error {
    border-color: var(--slds-g-color-error-1, #ea001e);
}

.recipe-input--error: focus {
    box-shadow: 0 0 0 3px var(--slds-g-color-error-container-1, #fef1f1);
}

Custom Button (Beyond lightning-button)

When lightning-button doesn't fit the design, use custom buttons that still respect SLDS hooks.

CSS
.recipe-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--slds-g-spacing-2, 0.5rem);
    padding: var(--slds-g-spacing-2, 0.5rem) var(--slds-g-spacing-4, 1rem);
    font-size: var(--slds-g-font-size-4, 0.875rem);
    font-weight: var(--slds-g-font-weight-6, 600);
    border-radius: var(--slds-g-radius-border-2, 0.25rem);
    border: var(--slds-g-sizing-border-1) solid transparent;
    cursor: pointer;
    transition: background-color 150ms ease, border-color 150ms ease;
}

.recipe-btn--primary {
    background: var(--slds-g-color-accent-1, #0176d3);
    color: var(--slds-g-color-on-accent-1, #ffffff);
}

.recipe-btn--primary: hover {
    background: var(--slds-g-color-accent-2, #014486);
}

.recipe-btn--secondary {
    background: transparent;
    color: var(--slds-g-color-accent-1, #0176d3);
    border-color: var(--slds-g-color-border-1, #e5e5e5);
}

.recipe-btn--secondary: hover {
    background: var(--slds-g-color-surface-container-1, #f8f8f8);
}

.recipe-btn--ghost {
    background: transparent;
    color: var(--slds-g-color-on-surface-1, #181818);
    border-color: transparent;
}

.recipe-btn--ghost: hover {
    background: var(--slds-g-color-surface-3, #f3f3f3);
}

.recipe-btn: focus-visible {
    outline: 2px solid var(--slds-g-color-accent-1, #0176d3);
    outline-offset: 2px;
}

.recipe-btn: disabled {
    background: var(--slds-g-color-disabled-container-1, #ecebea);
    color: var(--slds-g-color-on-disabled-1, #706e6b);
    cursor: not-allowed;
    border-color: transparent;
}
CSS
.recipe-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9000;
}

.recipe-dialog {
    background: var(--slds-g-color-surface-1, #ffffff);
    border-radius: var(--slds-g-radius-border-3, 0.5rem);
    box-shadow: var(--slds-g-shadow-4);
    max-width: 600px;
    width: 90%;
    max-height: 80vh;
    overflow-y: auto;
}

.recipe-dialog__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--slds-g-spacing-4, 1rem);
    border-bottom: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-1, #e5e5e5);
}

.recipe-dialog__body {
    padding: var(--slds-g-spacing-4, 1rem);
}

.recipe-dialog__footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--slds-g-spacing-3, 0.75rem);
    padding: var(--slds-g-spacing-3, 0.75rem) var(--slds-g-spacing-4, 1rem);
    border-top: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-1, #e5e5e5);
}

CSS Composition Patterns

Layering Hooks for Complex Effects

Combine SLDS hooks to create sophisticated visual treatments without hardcoded values.

CSS
/* Glassmorphism-inspired panel using SLDS hooks */
.frosted-panel {
    background: var(--slds-g-color-surface-1, #ffffff);
    border: var(--slds-g-sizing-border-1) solid var(--slds-g-color-border-1, #e5e5e5);
    border-radius: var(--slds-g-radius-border-3, 0.5rem);
    box-shadow: var(--slds-g-shadow-3);
    backdrop-filter: blur(8px);
}

/* Gradient accent bar using accessible palette */
.accent-bar {
    height: var(--slds-g-spacing-1, 0.25rem);
    background: linear-gradient(
        90deg,
        var(--slds-g-color-accent-1, #0176d3),
        var(--slds-g-color-accent-3, #1b96ff)
    );
    border-radius: var(--slds-g-radius-border-pill) var(--slds-g-radius-border-pill) 0 0;
}

Status Indicator Pattern

Reusable status dot + text pattern using feedback colors.

CSS
.status-indicator {
    display: inline-flex;
    align-items: center;
    gap: var(--slds-g-spacing-2, 0.5rem);
    font-size: var(--slds-g-font-size-3, 0.8125rem);
}

.status-dot {
    width: var(--slds-g-sizing-1, 0.5rem);
    height: var(--slds-g-sizing-1, 0.5rem);
    border-radius: var(--slds-g-radius-circle);
    flex-shrink: 0;
}

.status-dot--active { background: var(--slds-g-color-success-1, #2e844a); }
.status-dot--warning { background: var(--slds-g-color-warning-1, #dd7a01); }
.status-dot--error { background: var(--slds-g-color-error-1, #ea001e); }
.status-dot--inactive { background: var(--slds-g-color-disabled-1, #c9c7c5); }

Scoring Rubric (100 Points)Reference

Scoring Guide

  • 90-100: Exemplary — clean utility system, fully SLDS-native, composable
  • 70-89: Good — minor hardcoded values or missing fallbacks
  • 50-69: Needs rework — inconsistent naming, hardcoded colors
  • Below 50: Not utility-first — monolithic CSS, heavy overrides

Cross-Skill IntegrationReference

Anti-PatternsReference

Tailwind ConceptSLDS 2 HookCSS
bg-whitesurface-1background: var(--slds-g-color-surface-1, #fff)
bg-gray-50surface-container-1background: var(--slds-g-color-surface-container-1)
bg-gray-100surface-container-2background: var(--slds-g-color-surface-container-2)
bg-blue-50accent-container-1background: var(--slds-g-color-accent-container-1)
bg-red-50error-container-1background: var(--slds-g-color-error-container-1)
bg-green-50success-container-1background: var(--slds-g-color-success-container-1)
text-gray-900on-surface-1color: var(--slds-g-color-on-surface-1)
text-gray-500on-surface-2color: var(--slds-g-color-on-surface-2)
text-gray-400on-surface-3color: var(--slds-g-color-on-surface-3)
text-blue-600accent-1color: var(--slds-g-color-accent-1)
border-gray-200border-1border-color: var(--slds-g-color-border-1)
TailwindSLDS 2 HookApprox Value
p-1 / m-1--slds-g-spacing-10.25rem
p-2 / m-2--slds-g-spacing-20.5rem
p-3 / m-3--slds-g-spacing-30.75rem
p-4 / m-4--slds-g-spacing-41rem
p-5 / m-5--slds-g-spacing-51.25rem
p-6 / m-6--slds-g-spacing-61.5rem
p-8 / m-8--slds-g-spacing-82rem
p-10 / m-10--slds-g-spacing-102.5rem
p-12 / m-12--slds-g-spacing-123rem
TailwindSLDS 2 Hook
text-xs--slds-g-font-size-1
text-sm--slds-g-font-size-2
text-base--slds-g-font-size-4
text-lg--slds-g-font-size-5
text-xl--slds-g-font-size-7
text-2xl--slds-g-font-size-9
text-3xl--slds-g-font-size-11
font-normal--slds-g-font-weight-4
font-medium--slds-g-font-weight-5
font-semibold--slds-g-font-weight-6
font-bold--slds-g-font-weight-7
TailwindSLDS 2 Hook
rounded-sm--slds-g-radius-border-1
rounded--slds-g-radius-border-2
rounded-lg--slds-g-radius-border-3
rounded-xl--slds-g-radius-border-4
rounded-full--slds-g-radius-circle
rounded-pill--slds-g-radius-border-pill
TailwindSLDS 2 Hook
shadow-sm--slds-g-shadow-1
shadow--slds-g-shadow-2
shadow-lg--slds-g-shadow-3
shadow-xl--slds-g-shadow-4
CategoryPointsPass Criteria
SLDS Hook Usage25All visual values come from --slds-g- hooks; zero hardcoded colors/sizes
Utility Class Quality20Reusable, semantic naming; follows .util- or .recipe- conventions
Composition20CSS classes combine cleanly; no !important; no deep nesting (max 2 levels)
Fallback Values15Every var() includes a fallback for resilience
Theme-Safe10All patterns use --slds-g- hooks; no hardcoded values that break under alternate themes
Performance10No redundant declarations; efficient selectors; no wildcards
SkillRelationship
sf-lwc-designProvides the SLDS 2 hook reference that all utility classes map to
sf-lwc-uxUX patterns (loading, empty, error states) use these utility classes
sf-lwcProvides JS logic, wire service, events — this skill handles the CSS layer
Do NOTDo Instead
color: #181818color: var(--slds-g-color-on-surface-1, #181818)
padding: 16pxpadding: var(--slds-g-spacing-4, 1rem)
border-radius: 8pxborder-radius: var(--slds-g-radius-border-3, 0.5rem)
.slds-m-bottom_medium (SLDS 1)margin-bottom: var(--slds-g-spacing-4)
!important overridesSpecificity via component scoping
Deeply nested selectorsFlat utility classes (max 2 levels)

DependenciesReference

  • Target org with LWC support (API 45.0+)
  • SLDS 2 recommended (API 62.0+) for full styling hook support
  • No build tools, no npm packages, no static resources required