frontend-style-guide
Apply the Lightdash frontend style guide for React and Mantine migration tasks.
Install
mkdir -p .claude/skills/frontend-style-guide && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/6557" && unzip -o skill.zip -d .claude/skills/frontend-style-guide && rm skill.zipInstalls to .claude/skills/frontend-style-guide
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Apply the Lightdash frontend style guide when working on React components, migrating Mantine v6 to v8, or styling frontend code. Use when editing TSX files, fixing styling issues, or when user mentions Mantine, styling, or CSS modules.Key capabilities
- →Migrates components from Mantine v6 to v8
- →Enforces CSS module usage
- →Validates component prop counts
- →Applies themed styling variables
- →Enforces style guide component checklist
How it works
Applies a transformation rule-set based on the project's style guide and component migration requirements.
Inputs & outputs
When to use frontend-style-guide
- →Migrate Mantine component
- →Style React component
- →Enforce CSS module standards
- →Update theme values
About this skill
Lightdash Frontend Style Guide
Apply these rules when working on any frontend component in packages/frontend/.
Mantine 8 Migration
CRITICAL: We are migrating from Mantine 6 to 8. Always upgrade v6 components when you encounter them.
Component Checklist
When creating/updating components:
- Use
@mantine-8/coreimports - No
styleorstylesorsxprops - Check Mantine docs/types for available component props
- Use inline-style component props for styling when available (and follow <=3 props rule)
- Use CSS modules when component props aren't available or when more than 3 inline-style props are needed
- Theme values ('md', 'lg', 'xl', or 'ldGray.1', 'ldGray.2', 'ldDark.1', 'ldDark.2', etc) instead of magic numbers
- When using mantine colors in css modules, always use the theme awared variables:
--mantine-color-${color}-text: for text on filled background--mantine-color-${color}-filled: for filled background (strong color)--mantine-color-${color}-filled-hover: for filled background on hover--mantine-color-${color}-light: for light background--mantine-color-${color}-light-hover: for light background on hover (light color)--mantine-color-${color}-light-color: for text on light background--mantine-color-${color}-outline: for outlines--mantine-color-${color}-outline-hover: for outlines on hover
Quick Migration Guide
// ❌ Mantine 6
import { Button, Group } from '@mantine/core';
<Group spacing="xs" noWrap>
<Button sx={{ mt: 20 }}>Click</Button>
</Group>;
// ✅ Mantine 8
import { Button, Group } from '@mantine-8/core';
<Group gap="xs" wrap="nowrap">
<Button mt={20}>Click</Button>
</Group>;
Key Prop Changes
spacing→gapnoWrap→wrap="nowrap"sx→ Component props (e.g.,mt,w,c) or CSS modulesleftIcon→leftSectionrightIcon→rightSection
Styling Best Practices
Core Principle: Theme First
The goal is to use theme defaults whenever possible. Style overrides should be the exception, not the rule.
Styling Hierarchy
- Best: No custom styles (use theme defaults)
- Theme extension: For repeated patterns, add to
mantine8Theme.ts - Component props: Simple overrides (1-3 props like
mt="xl" w={240}) - CSS modules: Complex styling or more than 3 props
NEVER Use
stylesprop (always use CSS modules instead)sxprop (it's a v6 prop)styleprop (inline styles)
Theme Extensions (For Repeated Patterns)
If you find yourself applying the same style override multiple times, add it to the theme in mantine8Theme.ts:
// In src/mantine8Theme.ts - inside the components object
components: {
Button: Button.extend({
styles: {
root: {
minWidth: '120px',
fontWeight: 600,
}
}
}),
}
Context-Specific Overrides
Inline-style Component Props (1-3 simple props)
// ✅ Good
<Button mt="xl" w={240} c="blue.6">Submit</Button>
// ❌ Bad - Too many props, use CSS modules instead
<Button mt={20} mb={20} ml={10} mr={10} w={240} c="blue.6" bg="white">Submit</Button>
Common inline-style props:
- Layout:
mt,mb,ml,mr,m,p,pt,pb,pl,pr - Sizing:
w,h,maw,mah,miw,mih - Colors:
c(color),bg(background) - Font:
ff,fs,fw - Text:
ta,lh
CSS Modules (complex styles or >3 props)
Create a .module.css file in the same folder as the component:
/* Component.module.css */
.customCard {
transition: transform 0.2s ease;
cursor: pointer;
}
.customCard:hover {
transform: translateY(-2px);
box-shadow: var(--mantine-shadow-lg);
}
import styles from './Component.module.css';
<Card className={styles.customCard}>{/* content */}</Card>;
Do NOT include .css.d.ts files - Vite handles this automatically.
Color Guidelines
Prefer default component colors - Mantine handles theme switching automatically.
When you need custom colors, use our custom scales for dark mode compatibility:
// ❌ Bad - Standard Mantine colors (poor dark mode support)
<Text c="gray.6">Secondary text</Text>
// ✅ Good - ldGray for borders and neutral elements
<Text c="ldGray.6">Secondary text</Text>
// ✅ Good - ldDark for elements that appear dark in light mode
<Button bg="ldDark.8" c="ldDark.0">Dark button</Button>
// ✅ Good - Foreground/background variables
<Text c="foreground">Primary text</Text>
<Box bg="background">Main background</Box>
Custom Color Scales
| Token | Purpose |
|---|---|
ldGray.0-9 | Borders, subtle text, neutral UI elements |
ldDark.0-9 | Buttons/badges with dark backgrounds in light mode |
background | Page/card backgrounds |
foreground | Primary text color |
Dark Mode in CSS Modules
Use @mixin dark for theme-specific overrides:
.clickableRow {
&:hover {
background-color: var(--mantine-color-ldGray-0);
@mixin dark {
background-color: var(--mantine-color-ldDark-5);
}
}
}
Alternative: use CSS light-dark() function for single-line theme switching:
.clickableRow:hover {
background-color: light-dark(
var(--mantine-color-ldGray-0),
var(--mantine-color-ldDark-5)
);
}
Always Use Theme Tokens
// ❌ Bad - Magic numbers
<Box p={16} mt={24}>
// ✅ Good - Theme tokens
<Box p="md" mt="lg">
Beware of dependencies
If a component is migrated to use Mantine 8 Menu.Item, ensure its parent also uses Mantine 8 Menu
Remove Dead Styles
Before moving styles to CSS modules, check if they're actually needed:
// ❌ Unnecessary - display: block has no effect on flex children
<Flex justify="flex-end">
<Button style={{display: 'block'}}>Submit</Button>
</Flex>
// ✅ Better - Remove the style entirely
<Flex justify="flex-end">
<Button>Submit</Button>
</Flex>
Shared Layout CSS Variables (heights, widths, z-indexes)
Cross-cutting layout constants (navbar/header/banner/footer heights, page content widths, sidebar dimensions, dashboard header/tab heights and z-indexes) are exposed as global CSS variables so CSS modules can use them directly:
/* ✅ Reference the global var — resolves on :root everywhere */
.myPanel {
top: var(--dashboard-header-height);
max-width: var(--page-content-max-width-large);
}
/* ❌ Don't hardcode the literal — drifts from the source of truth */
.myPanel {
top: 50px;
}
// ❌ Don't bridge a constant into CSS via an inline style object
<div style={{ '--dashboard-header-height': `${DASHBOARD_HEADER_HEIGHT}px` }}>
Source of truth: the numeric values live in their */constants.ts files
(e.g. components/common/Page/constants.ts,
components/common/Dashboard/dashboard.constants.ts) and are registered as CSS
variables in src/mantine8CssVariablesResolver.ts (wired into Mantine8Provider
via Mantine's cssVariablesResolver). Read that file for the full list of available
var(--...) names before defining your own.
To add a new shared layout constant: add the number to the relevant
constants.ts, register it in mantine8CssVariablesResolver.ts, then reference
var(--your-name) in CSS. Don't re-declare the literal in a .module.css file and
don't pass it through an inline style. Keep using the numeric constant directly in
TS where you need it as a JS value (e.g. a Mantine h= prop).
Theme-Aware Component Logic
For JavaScript logic that needs to know the current theme:
import { useMantineColorScheme } from '@mantine/core';
const MyComponent = () => {
const { colorScheme } = useMantineColorScheme();
const iconColor = colorScheme === 'dark' ? 'blue.4' : 'blue.6';
// ...
};
Keep using mantine/core's clsx utility until we migrate to Mantine 8 fully
import { clsx } from '@mantine/core';
const MyComponent = () => {
return (
<div className={clsx('my-class', 'my-other-class')}>My Component</div>
);
};
Select/MultiSelect grouping has a different structure on Mantine 8
<Select
label="Your favorite library"
placeholder="Pick value"
data={[
{ group: 'Frontend', items: ['React', 'Angular'] },
{ group: 'Backend', items: ['Express', 'Django'] },
]}
/>
Reusable Components
Modals
- Always use
MantineModalfromcomponents/common/MantineModal- never use Mantine's Modal directly - See
stories/Modal.stories.tsxfor usage examples - For forms inside modals: use
idon the form andform="form-id"on the submit button - For alerts inside modals: use
Calloutwith variantsdanger,warning,info
Callouts
- Use
Calloutfromcomponents/common/Callout - Variants:
danger,warning,info
Empty / Unavailable Sections (dotted style)
<Paper variant="dotted">(alsoCard) renders a dashedldGray.3border with a transparent background — the house style for empty, placeholder, or unavailable sections. Defined inmantine8Theme.ts(paperDottedStyles); used by e.g.FavoritesPanelandAiAgentKnowledgeFilesSection.- Section failed to load: use
InlineErrorStatefromcomponents/common/InlineErrorState— a dotted Paper with a muted message and optionalonRetrybutton. Keep it quiet; a failing secondary panel shouldn't shout. - Placeholder values (stat tiles etc. with no data): render an em dash (
—) inldGray.5inside a dotted container rather than fake zeros or endless skeletons. Skeletons mean "loading", dotted means "nothing here". - Reserve
ErrorState/SuboptimalStatefor whole-page failures.
Polymorphic Clickable Containe
Content truncated.
When not to use it
- →Legacy projects not using Mantine
- →Simple scripts where styling isn't required
Prerequisites
Limitations
- →Hard constraint on v8 migration
- →Strict limit on inline styling props
How it compares
It performs specific version-based code migration and styling enforcement rather than generic code styling.
Compared to similar skills
frontend-style-guide side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| frontend-style-guide (this skill) | 1 | 2mo | No flags | Intermediate |
| web-artifacts-builder | 49 | 3mo | Review | Intermediate |
| accessibility-compliance | 45 | 2mo | No flags | Intermediate |
| radix-ui-design-system | 33 | 2mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by lightdash
View all by lightdash →You might also like
web-artifacts-builder
anthropics
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
accessibility-compliance
wshobson
Implement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.
radix-ui-design-system
sickn33
Build accessible design systems with Radix UI primitives. Headless component customization, theming strategies, and compound component patterns for production-grade UI libraries.
figma-integration
duongdev
Guides design-to-code workflow using Figma integration. Helps extract designs, analyze components, and generate implementation specs. Auto-activates when users mention Figma URLs, design implementation, component conversion, or design-to-code workflows. Works with /ccpm:planning:design-ui, design-approve, design-refine, and /ccpm:utils:figma-refresh commands.
frontend-code-review
langgenius
Trigger when the user requests a review of frontend files (e.g., `.tsx`, `.ts`, `.js`). Support both pending-change reviews and focused file reviews while applying the checklist rules.
figma-implement-design
openai
Translate Figma nodes into production-ready code with 1:1 visual fidelity using the Figma MCP workflow (design context, screenshots, assets, and project-convention translation). Trigger when the user provides Figma URLs or node IDs, or asks to implement designs or components that must match Figma specs. Requires a working Figma MCP server connection.