frontend-style-guide
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLightdash Frontend Style Guide
Lightdash前端样式指南
Apply these rules when working on any frontend component in .
packages/frontend/在中开发任何前端组件时,请遵循以下规则。
packages/frontend/Mantine 8 Migration
Mantine 8迁移
CRITICAL: We are migrating from Mantine 6 to 8. Always upgrade v6 components when you encounter them.
重要提示:我们正在从Mantine 6迁移至8。遇到v6组件时,请务必将其升级。
Component Checklist
组件检查清单
When creating/updating components:
- Use imports
@mantine-8/core - No or
styleorstylespropssx - 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:
- : for text on filled background
--mantine-color-${color}-text - : for filled background (strong color)
--mantine-color-${color}-filled - : for filled background on hover
--mantine-color-${color}-filled-hover - : for light background
--mantine-color-${color}-light - : for light background on hover (light color)
--mantine-color-${color}-light-hover - : for text on light background
--mantine-color-${color}-light-color - : for outlines
--mantine-color-${color}-outline - : for outlines on hover
--mantine-color-${color}-outline-hover
创建/更新组件时:
- 使用导入
@mantine-8/core - 禁止使用、
style或styles属性sx - 查阅Mantine文档/类型以了解可用的组件属性
- 可用时使用内联样式组件属性进行样式设置(并遵循≤3个属性规则)
- 当组件属性无法满足需求或需要超过3个内联样式属性时,使用CSS modules
- 使用主题值(如'md'、'lg'、'xl',或'ldGray.1'、'ldGray.2'、'ldDark.1'、'ldDark.2'等)而非魔法数字
- 在CSS modules中使用Mantine颜色时,请始终使用主题感知变量:
- :用于填充背景上的文本
--mantine-color-${color}-text - :用于填充背景(纯色)
--mantine-color-${color}-filled - :用于悬停时的填充背景
--mantine-color-${color}-filled-hover - :用于浅色背景
--mantine-color-${color}-light - :用于悬停时的浅色背景
--mantine-color-${color}-light-hover - :用于浅色背景上的文本
--mantine-color-${color}-light-color - :用于轮廓
--mantine-color-${color}-outline - :用于悬停时的轮廓
--mantine-color-${color}-outline-hover
Quick Migration Guide
快速迁移指南
tsx
// ❌ 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>;tsx
// ❌ 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
核心属性变更
- →
spacinggap - →
noWrapwrap="nowrap" - → Component props (e.g.,
sx,mt,w) or CSS modulesc - →
leftIconleftSection - →
rightIconrightSection
- →
spacinggap - →
noWrapwrap="nowrap" - → 组件属性(如
sx、mt、w)或CSS modulesc - →
leftIconleftSection - →
rightIconrightSection
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
- 最佳选择:不使用自定义样式(使用主题默认值)
- 主题扩展:对于重复样式模式,添加至
mantine8Theme.ts - 组件属性:简单覆写(1-3个属性,如)
mt="xl" w={240} - CSS modules:复杂样式或超过3个属性时使用
NEVER Use
禁止使用
- prop (always use CSS modules instead)
styles - prop (it's a v6 prop)
sx - prop (inline styles)
style
- 属性(请始终使用CSS modules替代)
styles - 属性(属于v6属性)
sx - 属性(内联样式)
style
Theme Extensions (For Repeated Patterns)
主题扩展(针对重复样式模式)
If you find yourself applying the same style override multiple times, add it to the theme in :
mantine8Theme.tstsx
// In src/mantine8Theme.ts - inside the components object
components: {
Button: Button.extend({
styles: {
root: {
minWidth: '120px',
fontWeight: 600,
}
}
}),
}如果发现自己多次应用相同的样式覆写,请将其添加至中的主题配置:
mantine8Theme.tstsx
// 在src/mantine8Theme.ts的components对象内
components: {
Button: Button.extend({
styles: {
root: {
minWidth: '120px',
fontWeight: 600,
}
}
}),
}Context-Specific Overrides
特定上下文覆写
Inline-style Component Props (1-3 simple props)
内联样式组件属性(1-3个简单属性)
tsx
// ✅ 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,plpr - Sizing: ,
w,h,maw,mah,miwmih - Colors: (color),
c(background)bg - Font: ,
ff,fsfw - Text: ,
talh
tsx
// ✅ 推荐
<Button mt="xl" w={240} c="blue.6">Submit</Button>
// ❌ 不推荐 - 属性过多,请使用CSS modules替代
<Button mt={20} mb={20} ml={10} mr={10} w={240} c="blue.6" bg="white">Submit</Button>常用内联样式属性:
- 布局:,
mt,mb,ml,mr,m,p,pt,pb,plpr - 尺寸:,
w,h,maw,mah,miwmih - 颜色:(文本颜色),
c(背景色)bg - 字体:,
ff,fsfw - 文本:,
talh
CSS Modules (complex styles or >3 props)
CSS modules(复杂样式或>3个属性)
Create a file in the same folder as the component:
.module.csscss
/* Component.module.css */
.customCard {
transition: transform 0.2s ease;
cursor: pointer;
}
.customCard:hover {
transform: translateY(-2px);
box-shadow: var(--mantine-shadow-lg);
}tsx
import styles from './Component.module.css';
<Card className={styles.customCard}>{/* content */}</Card>;Do NOT include files - Vite handles this automatically.
.css.d.ts在组件所在文件夹中创建文件:
.module.csscss
/* Component.module.css */
.customCard {
transition: transform 0.2s ease;
cursor: pointer;
}
.customCard:hover {
transform: translateY(-2px);
box-shadow: var(--mantine-shadow-lg);
}tsx
import styles from './Component.module.css';
<Card className={styles.customCard}>{/* content */}</Card>;请勿包含文件 - Vite会自动处理此内容。
.css.d.tsColor Guidelines
颜色指南
Prefer default component colors - Mantine handles theme switching automatically.
When you need custom colors, use our custom scales for dark mode compatibility:
tsx
// ❌ 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>优先使用组件默认颜色 - Mantine会自动处理主题切换。
当需要自定义颜色时,请使用我们的自定义色阶以支持深色模式:
tsx
// ❌ 不推荐 - 标准Mantine颜色(深色模式支持较差)
<Text c="gray.6">次要文本</Text>
// ✅ 推荐 - ldGray用于边框和中性元素
<Text c="ldGray.6">次要文本</Text>
// ✅ 推荐 - ldDark用于浅色模式下的深色背景元素
<Button bg="ldDark.8" c="ldDark.0">深色按钮</Button>
// ✅ 推荐 - 前景/背景变量
<Text c="foreground">主要文本</Text>
<Box bg="background">主背景</Box>Custom Color Scales
自定义色阶
| Token | Purpose |
|---|---|
| Borders, subtle text, neutral UI elements |
| Buttons/badges with dark backgrounds in light mode |
| Page/card backgrounds |
| Primary text color |
| 令牌 | 用途 |
|---|---|
| 边框、次要文本、中性UI元素 |
| 浅色模式下带有深色背景的按钮/徽章 |
| 页面/卡片背景 |
| 主要文本颜色 |
Dark Mode in CSS Modules
CSS modules中的深色模式
Use for theme-specific overrides:
@mixin darkcss
.clickableRow {
&:hover {
background-color: var(--mantine-color-ldGray-0);
@mixin dark {
background-color: var(--mantine-color-ldDark-5);
}
}
}Alternative: use CSS function for single-line theme switching:
light-dark()css
.clickableRow:hover {
background-color: light-dark(
var(--mantine-color-ldGray-0),
var(--mantine-color-ldDark-5)
);
}使用进行主题特定覆写:
@mixin darkcss
.clickableRow {
&:hover {
background-color: var(--mantine-color-ldGray-0);
@mixin dark {
background-color: var(--mantine-color-ldDark-5);
}
}
}替代方案:使用CSS 函数实现单行主题切换:
light-dark()css
.clickableRow:hover {
background-color: light-dark(
var(--mantine-color-ldGray-0),
var(--mantine-color-ldDark-5)
);
}Always Use Theme Tokens
始终使用主题令牌
tsx
// ❌ Bad - Magic numbers
<Box p={16} mt={24}>
// ✅ Good - Theme tokens
<Box p="md" mt="lg">tsx
// ❌ 不推荐 - 魔法数字
<Box p={16} mt={24}>
// ✅ 推荐 - 主题令牌
<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
如果某个组件已迁移为使用Mantine 8的Menu.Item,请确保其父组件也使用Mantine 8的Menu
Remove Dead Styles
移除无用样式
Before moving styles to CSS modules, check if they're actually needed:
tsx
// ❌ 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>在将样式迁移至CSS modules之前,请检查这些样式是否真的有必要:
tsx
// ❌ 不必要 - display: block在flex子元素上无效
<Flex justify="flex-end">
<Button style={{display: 'block'}}>Submit</Button>
</Flex>
// ✅ 优化 - 完全移除该样式
<Flex justify="flex-end">
<Button>Submit</Button>
</Flex>Theme-Aware Component Logic
主题感知组件逻辑
For JavaScript logic that needs to know the current theme:
tsx
import { useMantineColorScheme } from '@mantine/core';
const MyComponent = () => {
const { colorScheme } = useMantineColorScheme();
const iconColor = colorScheme === 'dark' ? 'blue.4' : 'blue.6';
// ...
};对于需要了解当前主题的JavaScript逻辑:
tsx
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
在完全迁移至Mantine 8之前,请继续使用mantine/core的clsx工具
tsx
import { clsx } from '@mantine/core';
const MyComponent = () => {
return (
<div className={clsx('my-class', 'my-other-class')}>My Component</div>
);
};tsx
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
Mantine 8中Select/MultiSelect的分组结构有所不同
tsx
<Select
label="Your favorite library"
placeholder="Pick value"
data={[
{ group: 'Frontend', items: ['React', 'Angular'] },
{ group: 'Backend', items: ['Express', 'Django'] },
]}
/>tsx
<Select
label="你最喜爱的库"
placeholder="选择值"
data={[
{ group: '前端', items: ['React', 'Angular'] },
{ group: '后端', items: ['Express', 'Django'] },
]}
/>Reusable Components
可复用组件
Modals
模态框
- Always use from
MantineModal- never use Mantine's Modal directlycomponents/common/MantineModal - See for usage examples
stories/Modal.stories.tsx - For forms inside modals: use on the form and
idon the submit buttonform="form-id" - For alerts inside modals: use with variants
Callout,danger,warninginfo
- 请始终使用中的
components/common/MantineModal- 切勿直接使用Mantine的ModalMantineModal - 用法示例请查看
stories/Modal.stories.tsx - 模态框内的表单:为表单添加,并在提交按钮上使用
idform="form-id" - 模态框内的提示:使用组件,变体包括
Callout、danger、warninginfo
Callouts
提示框
- Use from
Calloutcomponents/common/Callout - Variants: ,
danger,warninginfo
- 使用中的
components/common/Callout组件Callout - 变体:、
danger、warninginfo
Polymorphic Clickable Containers
多态可点击容器
Use these when you need a layout container that is also clickable — avoids the native background/border reset problem.
<button>- from
PolymorphicGroupButton— acomponents/common/PolymorphicGroupButton(flex row) that is polymorphic and setsGroup. Use for horizontal groups of elements that act as a single button.cursor: pointer - from
PolymorphicPaperButton— acomponents/common/PolymorphicPaperButton(card surface) that is polymorphic and setsPaper. Use for card-like clickable surfaces.cursor: pointer
Both accept all props of their base component ( / ) plus a prop for the underlying element.
GroupPropsPaperPropscomponenttsx
// ✅ Clickable row without native button style bleed
<PolymorphicGroupButton component="div" gap="sm" onClick={handleClick}>
<MantineIcon icon={IconFolder} />
<Text>Label</Text>
</PolymorphicGroupButton>
// ✅ Clickable card surface
<PolymorphicPaperButton component="div" p="md" onClick={handleClick}>
Card content
</PolymorphicPaperButton>
// ❌ Avoid - native <button> brings unwanted background/border in menus and panels
<UnstyledButton>
<Group>...</Group>
</UnstyledButton>当你需要一个同时可点击的布局容器时,请使用以下组件 — 避免原生的背景/边框重置问题。
<button>- 中的
components/common/PolymorphicGroupButton— 一个多态的PolymorphicGroupButton(弹性行),设置了Group。用于可作为单个按钮的水平元素组。cursor: pointer - 中的
components/common/PolymorphicPaperButton— 一个多态的PolymorphicPaperButton(卡片表面),设置了Paper。用于卡片式可点击表面。cursor: pointer
两者均接受其基础组件的所有属性( / ),以及用于设置底层元素的属性。
GroupPropsPaperPropscomponenttsx
// ✅ 无原生按钮样式渗透的可点击行
<PolymorphicGroupButton component="div" gap="sm" onClick={handleClick}>
<MantineIcon icon={IconFolder} />
<Text>标签</Text>
</PolymorphicGroupButton>
// ✅ 可点击卡片表面
<PolymorphicPaperButton component="div" p="md" onClick={handleClick}>
卡片内容
</PolymorphicPaperButton>
// ❌ 避免使用 - 原生<button>会在菜单和面板中带来不必要的背景/边框
<UnstyledButton>
<Group>...</Group>
</UnstyledButton>EmptyStateLoader
EmptyStateLoader
- Use from
EmptyStateLoaderfor any centered loading state: page-level guards, panels, tables, empty containerscomponents/common/EmptyStateLoader - Built on (Mantine v8) — renders a spinner with an optional title, fully centered in its parent
SuboptimalState
- 任何居中加载状态(页面级守卫、面板、表格、空容器)都请使用中的
components/common/EmptyStateLoaderEmptyStateLoader - 基于(Mantine v8)构建 — 渲染带可选标题的加载器,并在父容器中完全居中
SuboptimalState
TruncatedText
TruncatedText
- Use from
TruncatedTextwhenever text may overflow a constrained widthcomponents/common/TruncatedText - Pass (number or string) to control the truncation boundary
maxWidth - Automatically shows a tooltip with the full text only when the text is actually truncated (no tooltip spam for short names)
- Defaults to ; override via standard
fz="sm"propsText
tsx
// ✅ Good - truncates long names, tooltip only appears when needed
<TruncatedText maxWidth={200}>{item.name}</TruncatedText>
// ✅ Accepts any Text prop
<TruncatedText maxWidth="100%" fw={500}>{space.name}</TruncatedText>- 当文本可能超出限制宽度时,请使用中的
components/common/TruncatedText组件TruncatedText - 传递(数字或字符串)以控制截断边界
maxWidth - 仅当文本确实被截断时才自动显示包含完整文本的提示框(避免短文本的提示框干扰)
- 默认字体大小为;可通过标准
fz="sm"属性覆盖Text
tsx
// ✅ 推荐 - 截断长名称,仅在需要时显示提示框
<TruncatedText maxWidth={200}>{item.name}</TruncatedText>
// ✅ 支持任何Text属性
<TruncatedText maxWidth="100%" fw={500}>{space.name}</TruncatedText>Mantine Documentation
Mantine文档
List of all components and links to their documentation in LLM-friendly format:
https://mantine.dev/llms.txt所有组件列表及其LLM友好格式的文档链接:
https://mantine.dev/llms.txt