Frontend Styling
XinAdmin uses Tailwind CSS v4 + Ant Design to build its styling system, controlling style priority through CSS Layers and enabling component-level style customization via Ant Design's Semantic DOM.
For more details on Ant Design styling, refer to Ant Design Compatible Style Documentation.
Style Architecture
┌──────────────────────────────────────────┐
│ Application Style Layer │
│ Tailwind utilities + custom styles prop │
│ Highest priority, overrides antd defaults│
├──────────────────────────────────────────┤
│ Ant Design Style Layer │
│ CSS-in-JS generated component styles │
│ ConfigProvider theme token global control│
├──────────────────────────────────────────┤
│ Base Style Layer │
│ Tailwind base (reset + global styles) │
└──────────────────────────────────────────┘
1. Tailwind CSS v4
1.1 Integration
XinAdmin integrates Tailwind CSS v4 via the Vite plugin, requiring no tailwind.config file:
// vite.config.ts
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [
react(),
tailwindcss(), // Tailwind v4 Vite plugin
],
});
1.2 CSS Layer Configuration
/* web/index.css */
@layer theme, base, antd, components, utilities;
@import "tailwindcss";
Key design: Placing antd layer before components and utilities ensures Tailwind utilities and custom component styles can override Ant Design defaults without needing !important.
Note: If Ant Design's CSS-in-JS output is not placed in the antd layer, wrap your app with <StyleProvider layer> from @ant-design/cssinjs. See Ant Design Compatible Style Documentation.
1.3 Tailwind v4 Features
The project uses these Tailwind v4 features:
1.4 Common Utility Classes
Widely used Tailwind classes across the project:
1.5 Using Tailwind with Ant Design
// Quick layout and spacing adjustments with Tailwind classes
<Card className="mb-5 p-2.5">
<Space className="flex justify-between items-center">
<Button type="primary" className="rounded-lg font-semibold">
Submit
</Button>
<Input className="w-60" placeholder="Search" />
</Space>
</Card>
2. Ant Design Theme System
2.1 ConfigProvider Global Theme
The AntdProvider component manages global theme tokens:
// components/AntdProvider/index.tsx
const theme: ThemeConfig = useMemo(() => ({
components: {
Layout: {
headerHeight: themeConfig.headerHeight,
bodyBg: themeConfig.bodyBg,
headerBg: themeConfig.headerBg,
siderBg: themeConfig.siderBg,
// ...
},
Menu: {
activeBarBorderWidth: 0,
itemBg: 'transparent',
subMenuItemBg: 'transparent',
},
},
token: {
colorPrimary: themeConfig.colorPrimary,
colorBgBase: themeConfig.colorBg,
colorTextBase: themeConfig.colorText,
borderRadius: themeConfig.borderRadius,
controlHeight: themeConfig.controlHeight,
// ... error / success / warning / info / link
},
algorithm: themeConfig.algorithm ? algorithm[themeConfig.algorithm] : undefined,
}), [themeConfig]);
2.2 Tokens and Algorithms
Four theme algorithms:
2.3 useToken Runtime Theme Values
Get current theme token values for dynamic inline styles:
import { theme } from 'antd';
const { useToken } = theme;
function MyComponent() {
const { token } = useToken();
return (
<div
style={{
background: token.colorPrimaryBg,
color: token.colorText,
borderColor: token.colorBorder,
borderRadius: token.borderRadius,
boxShadow: token.boxShadow,
}}
>
Content
</div>
);
}
Places where useToken is used in the project:
layout/SettingDrawer.tsx — Layout thumbnails in theme settings
layout/ColumnsMenu.tsx — Selected highlight color in columns menu
layout/HeaderRightRender.tsx — Divider color in search modal
pages/dashboard/analysis.tsx — Dashboard cards and chart colors
2.4 Theme Persistence
Theme configuration is persisted to localStorage via Zustand store:
// stores/global/index.ts
const useGlobalStore = create<GlobalStore>()(
persist(
(...args) => ({ ...globalState, ...globalAction(...args) }),
{
name: 'global-storage',
storage: createJSONStorage(() => localStorage),
}
)
);
Users can visually modify theme settings via SettingDrawer. All changes take effect in real-time with 400ms debounce and auto-save.
3. Ant Design Semantic DOM
3.1 What is Semantic DOM
Ant Design v5+ defines stable semantic names for each component's internal elements. The classNames and styles props allow precise style overrides targeting specific child elements without depending on internal DOM class names.
// Precise style overrides using Semantic DOM
<Input
classNames={{
root: 'my-custom-input-root', // Component root element
input: 'my-custom-input-inner', // Input element itself
prefix: 'my-custom-input-prefix', // Prefix area
suffix: 'my-custom-input-suffix', // Suffix area
}}
styles={{
root: { marginBottom: 16 },
input: { fontSize: 14, color: '#333' },
prefix: { color: '#999' },
}}
/>
3.2 Common Component Semantic Names
3.3 Usage of styles in the Project
The project uses Semantic DOM's styles prop in several places:
// MobileDrawerMenu.tsx - Custom Drawer sub-area styles
<Drawer
styles={{
section: { width: 280 },
header: {
borderBottom: '1px solid ' + themeConfig.colorBorder,
background: themeConfig.siderBg,
color: themeConfig.siderColor,
},
body: { padding: 0, background: themeConfig.siderBg },
}}
/>
// XinTable/index.tsx - Custom Modal header spacing
<XinForm
modalProps={{
styles: { header: { marginBottom: 16 } },
}}
/>
// SettingDrawer.tsx - Adjust Drawer body top padding
<Drawer styles={{ body: { paddingTop: 10 } }} />
3.4 Combining classNames with Tailwind
classNames integrates seamlessly with Tailwind CSS for quick component style overrides:
<Button
classNames={{
root: 'bg-primary rounded-lg hover:opacity-90',
icon: 'text-white/90',
content: 'font-semibold',
}}
icon={<PlusOutlined />}
>
Create
</Button>
<Input
classNames={{
root: 'shadow-sm hover:shadow-md transition-shadow',
input: 'font-mono text-sm',
}}
/>
<Modal
classNames={{
body: 'px-8 py-6',
footer: 'border-t border-gray-100',
}}
/>
4. Style Override Strategies
XinAdmin uses three style override approaches for different scenarios:
Recommended Override Order
- Global theme → Use
ConfigProvider theme tokens
- Component defaults → Use
ConfigProvider components component-level tokens
- Single component customization → Use
classNames + Tailwind utilities
- Dynamic theme colors → Use
styles or useToken + inline style
Global Style Override Example
/* Override antd component library global defaults if needed */
@layer components {
.ant-table-thead > tr > th {
font-weight: 600;
text-transform: uppercase;
font-size: 12px;
letter-spacing: 0.05em;
}
}
5. Custom Loading Styles
The project overrides Ant Design Spin component animation styles via a classic CSS file:
/* components/Loading/index.css */
.ant-spin-dot-item {
background: var(--ant-color-primary); /* Follows theme color */
}
.ant-spin-spinning {
/* Custom animation */
}
Uses Ant Design's CSS variable system --ant-color-primary to ensure the loading indicator follows theme color changes.
6. References