From ede80dc2adc97d77dd2f4a4cb60c899deeca878f Mon Sep 17 00:00:00 2001
From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com>
Date: Tue, 1 Jul 2025 19:16:14 +0000
Subject: [PATCH 1/3] docs: update frontend contributing guide for shadcn/ui
and TailwindCSS migration
Update the frontend contributing guide to reflect the current architecture
and ongoing migration from MUI to shadcn/ui and from Emotion to TailwindCSS.
Key changes:
- Updated tech stack to include TailwindCSS, shadcn/ui, Lucide React, and Biome
- Added migration status section with current progress (~210 MUI files, ~41 migrated)
- Added development commands section with pnpm commands and pre-PR checklist
- Rewrote UI components section to prioritize shadcn/ui over MUI
- Completely updated styling section to focus on TailwindCSS
- Enhanced accessibility section with TailwindCSS examples
- Added comprehensive migration guide with practical examples and checklists
- Documented semantic color system and best practices
Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
---
docs/about/contributing/frontend.md | 364 +++++++++++++++++++++++++---
1 file changed, 334 insertions(+), 30 deletions(-)
diff --git a/docs/about/contributing/frontend.md b/docs/about/contributing/frontend.md
index ceddc5c2ff819..a70c06c2d4ce7 100644
--- a/docs/about/contributing/frontend.md
+++ b/docs/about/contributing/frontend.md
@@ -26,6 +26,40 @@ In both cases, you can access the dashboard on `http://localhost:8080`. If using
> [!NOTE]
> **Default Credentials:** `admin@coder.com` and `SomeSecurePassword!`.
+## Development Commands
+
+All commands should be run from the `site/` directory:
+
+```bash
+# Development
+pnpm dev # Start Vite development server
+pnpm storybook --no-open # Run Storybook for component development
+
+# Testing
+pnpm test # Run Jest unit tests
+pnpm test -- path/to/file # Run specific test file
+pnpm playwright:test # Run Playwright E2E tests (requires license)
+
+# Code Quality
+pnpm lint # Run complete linting suite (Biome + TypeScript + circular deps + knip)
+pnpm lint:fix # Auto-fix linting issues where possible
+pnpm format # Format code with Biome (always run before PR)
+pnpm check # Type-check with TypeScript
+
+# Build
+pnpm build # Production build
+```
+
+### Pre-PR Checklist
+
+Before creating a pull request, ensure you run:
+
+1. `pnpm check` - Ensure no TypeScript errors
+2. `pnpm lint` - Fix linting issues
+3. `pnpm format` - Format code consistently
+4. `pnpm test` - Run affected unit tests
+5. Visual check in Storybook if component changes
+
## Tech Stack Overview
All our dependencies are described in `site/package.json`, but the following are
@@ -34,7 +68,9 @@ the most important.
- [React](https://reactjs.org/) for the UI framework
- [Typescript](https://www.typescriptlang.org/) to keep our sanity
- [Vite](https://vitejs.dev/) to build the project
-- [Material V5](https://mui.com/material-ui/getting-started/) for UI components
+- [TailwindCSS](https://tailwindcss.com/) for styling (migrating from Emotion)
+- [shadcn/ui](https://ui.shadcn.com/) + [Radix UI](https://www.radix-ui.com/) for UI components (migrating from Material UI)
+- [Lucide React](https://lucide.dev/) for icons
- [react-router](https://reactrouter.com/en/main) for routing
- [TanStack Query v4](https://tanstack.com/query/v4/docs/react/overview) for
fetching data
@@ -43,8 +79,42 @@ the most important.
- [Jest](https://jestjs.io/) for integration testing
- [Storybook](https://storybook.js.org/) and
[Chromatic](https://www.chromatic.com/) for visual testing
+- [Biome](https://biomejs.dev/) for linting and formatting
- [PNPM](https://pnpm.io/) as the package manager
+## Migration Status
+
+**⚠️ Important: We are currently migrating from Material UI (MUI) to shadcn/ui and from Emotion to TailwindCSS.**
+
+### Current State
+- **~210 files** still use MUI components (`@mui/material`)
+- **~41 components** have been migrated to use TailwindCSS classes
+- **shadcn/ui components** are being added incrementally to `src/components/`
+- **Emotion CSS** is deprecated but still present in legacy components
+
+### Migration Guidelines
+
+When working on existing components:
+1. **Prefer shadcn/ui components** over MUI when available
+2. **Use TailwindCSS classes** instead of Emotion `css` prop or `sx` prop
+3. **Check `src/components/`** for existing shadcn/ui implementations before creating new ones
+4. **Do not use the shadcn CLI** - manually add components to maintain consistency
+5. **Update tests** to reflect new component structure when migrating
+
+For new components:
+1. **Always use TailwindCSS** for styling
+2. **Use shadcn/ui components** as the foundation
+3. **Use Lucide React icons** instead of MUI icons
+4. **Follow the semantic color tokens** defined in `tailwind.config.js`
+
+### Semantic Color System
+
+Use the custom semantic color tokens defined in our Tailwind configuration:
+- **Content colors**: `content-primary`, `content-secondary`, `content-disabled`, `content-invert`, `content-success`, `content-link`, `content-destructive`, `content-warning`
+- **Surface colors**: `surface-primary`, `surface-secondary`, `surface-tertiary`, `surface-quaternary`, `surface-invert-primary`, `surface-invert-secondary`, `surface-destructive`, `surface-green`, `surface-grey`, `surface-orange`, `surface-sky`, `surface-red`, `surface-purple`
+- **Border colors**: `border-default`, `border-warning`, `border-destructive`, `border-success`, `border-hover`
+- **Highlight colors**: `highlight-purple`, `highlight-green`, `highlight-grey`, `highlight-sky`, `highlight-red`
+
## Structure
All UI-related code is in the `site` folder. Key directories include:
@@ -182,13 +252,36 @@ Components should be atomic, reusable and free of business logic. Modules are
similar to components except that they can be more complex and can contain
business logic specific to the product.
-### MUI
+### UI Components
+
+**⚠️ MUI is deprecated** - we are migrating to shadcn/ui + Radix UI.
+
+#### shadcn/ui Components (Preferred)
+
+We use [shadcn/ui](https://ui.shadcn.com/) components built on top of [Radix UI](https://www.radix-ui.com/) primitives. These components are:
+- **Accessible by default** with ARIA attributes and keyboard navigation
+- **Customizable** with TailwindCSS classes
+- **Consistent** with our design system
+- **Type-safe** with full TypeScript support
+
+Existing shadcn/ui components can be found in `src/components/`. Examples include:
+- `Checkbox` - Form checkbox input
+- `ScrollArea` - Custom scrollable area
+- `Table` - Data table with sorting and filtering
+- `Slider` - Range input slider
+- `Switch` - Toggle switch
+- `Command` - Command palette/search
+- `Collapsible` - Expandable content sections
-The codebase is currently using MUI v5. Please see the
-[official documentation](https://mui.com/material-ui/getting-started/). In
-general, favor building a custom component via MUI instead of plain React/HTML,
-as MUI's suite of components is thoroughly battle-tested and accessible right
-out of the box.
+#### MUI Components (Legacy)
+
+The codebase still contains MUI v5 components that are being phased out. When encountering MUI components:
+1. **Check if a shadcn/ui equivalent exists** in `src/components/`
+2. **Migrate to the shadcn/ui version** when making changes
+3. **Create a new shadcn/ui component** if no equivalent exists
+4. **Do not add new MUI components** to the codebase
+
+For reference, the [MUI documentation](https://mui.com/material-ui/getting-started/) can still be consulted for understanding existing legacy components.
### Structure
@@ -199,35 +292,65 @@ remain easy to navigate, healthy and maintainable for all contributors.
### Accessibility
-We strive to keep our UI accessible.
+We strive to keep our UI accessible. **shadcn/ui components are accessible by default** with proper ARIA attributes, keyboard navigation, and focus management.
+
+#### Color Contrast
+
+Colors should come from our semantic color tokens in the Tailwind theme. These tokens are designed to meet WCAG level AA compliance (4.5:1 contrast ratio). If you need to add a custom color, ensure proper contrast using:
+- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
+- [Dequeue's axe DevTools](https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd)
+
+#### Form Labels
+
+Always associate labels with input elements. Labels can be visually hidden but must be present in the markup for screen readers.
+
+```tsx
+// ✅ Good: Visible label
+
+
+
+// ✅ Good: Visually hidden label
+
+
+```
+
+#### Images and Icons
-In general, colors should come from the app theme, but if there is a need to add
-a custom color, please ensure that the foreground and background have a minimum
-contrast ratio of 4.5:1 to meet WCAG level AA compliance. WebAIM has
-[a great tool for checking your colors directly](https://webaim.org/resources/contrastchecker/),
-but tools like
-[Dequeue's axe DevTools](https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd)
-can also do automated checks in certain situations.
+Provide descriptive text for images and icons:
-When using any kind of input element, always make sure that there is a label
-associated with that element (the label can be made invisible for aesthetic
-reasons, but it should always be in the HTML markup). Labels are important for
-screen-readers; a placeholder text value is not enough for all users.
+```tsx
+// ✅ Good: Alt text for images
+
+
+// ✅ Good: Screen reader text for icons
+
+
+// ✅ Good: Using Lucide React icons with proper labeling
+import { Settings } from "lucide-react";
+
+```
+
+#### Legacy MUI Accessibility
-When possible, make sure that all image/graphic elements have accompanying text
-that describes the image. `
` elements should have an `alt` text value. In
-other situations, it might make sense to place invisible, descriptive text
-inside the component itself using MUI's `visuallyHidden` utility function.
+For legacy MUI components, you may still see the `visuallyHidden` utility:
```tsx
+// ❌ Legacy: MUI visuallyHidden
import { visuallyHidden } from "@mui/utils";
+