refactor(ui): Replace raw Tailwind color classes with project design tokens #12033
refactor(ui): Replace raw Tailwind color classes with project design tokens #12033Cristhianzl wants to merge 3 commits intomainfrom
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThis pull request systematically updates color utility classes across the frontend codebase to use semantic design tokens from a design system instead of hard-coded Tailwind colors. Changes affect status indicators, buttons, text, borders, and other UI elements while preserving all layout and functionality. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 5 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsx (1)
26-30:⚠️ Potential issue | 🟡 MinorAdd type annotation for the
themeparameter.The
themeparameter lacks TypeScript typing, which reduces type safety.💡 Proposed fix
- const handleThemeChange = (theme) => { + const handleThemeChange = (theme: "light" | "dark" | "system") => { setHasInteracted(true); // Mark that a button has been clicked setSelectedTheme(theme); setThemePreference(theme); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsx` around lines 26 - 30, handleThemeChange currently accepts an untyped theme parameter; add a TypeScript type annotation to the parameter (e.g. change the signature of handleThemeChange to handleThemeChange(theme: ThemePreference) or handleThemeChange(theme: 'light'|'dark'|'system') depending on your existing types) so calls to setHasInteracted, setSelectedTheme and setThemePreference are type-safe; import or reference the existing Theme/ThemePreference type if available, otherwise declare the explicit union string type in this file.
🧹 Nitpick comments (3)
src/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsx (1)
52-64: Consider using thecn()utility for conditional class composition.The coding guidelines recommend using the
cn()utility function for combining Tailwind CSS classes. This would improve readability and maintainability of the conditional styling logic. However, since this is a pre-existing pattern and the PR focuses on token replacement, this can be addressed separately.♻️ Example refactor using cn()
import { cn } from "@/utils/utils"; // Then in the Button: <Button unstyled className={cn( "relative z-10 inline-flex items-center rounded-full px-1", selectedTheme === "light" ? "text-foreground" : "text-foreground hover:bg-accent-amber-foreground hover:text-background" )} onClick={() => handleThemeChange("light")} data-testid="menu_light_button" id="menu_light_button" >As per coding guidelines: "Use the cn() utility function for combining Tailwind CSS classes in components".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsx` around lines 52 - 64, Replace the inline conditional className string in the ThemeButtons component's Button (the element rendering ForwardedIconComponent with id/data-testid "menu_light_button") to use the cn() utility for class composition; import cn from "@/utils/utils" (or existing utils file) and pass the static classes ("relative z-10 inline-flex items-center rounded-full px-1") and the conditional classes (selectedTheme === "light" ? "text-foreground" : "text-foreground hover:bg-accent-amber-foreground hover:text-background") as separate arguments to cn() so the conditional styling is clearer and consistent with project conventions.src/frontend/src/components/core/jsonEditor/index.tsx (1)
395-398: Consider usingbg-accent-emeraldinstead ofbg-accent-emerald-foregroundfor background color.The code (though commented out) uses
bg-accent-emerald-foregroundfor button background. Typically,-foregroundtokens are designed for text colors, while the base token (accent-emerald) is intended for backgrounds. Based on the Tailwind config snippet provided,accent-emeraldexists as a separate token.🔧 Suggested semantic correction
className={cn( "min-w-[60px] whitespace-nowrap", - showSuccess && "!bg-accent-emerald-foreground hover:!bg-accent-emerald-foreground/90", + showSuccess && "!bg-accent-emerald hover:!bg-accent-emerald-hover", )}Note: This code is currently commented out, so this is a low-priority suggestion for when it gets re-enabled.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/frontend/src/components/core/jsonEditor/index.tsx` around lines 395 - 398, The className conditional uses the token "bg-accent-emerald-foreground" for the success background; change it to the background token "bg-accent-emerald" where showSuccess is applied so the button uses the intended background color (update the className expression that calls cn with showSuccess, referencing the same cn utility and the showSuccess boolean in this component).src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx (1)
771-786: Minor inconsistency in Delete option styling tokens.The Delete option uses
text-status-redfor the text/icon container (line 772) buttext-destructivefor the keyboard shortcut icon (line 783). Consider unifying these to use the same token for consistency, unlesstext-status-redis intentionally a different semantic color thantext-destructive.🔧 Suggested fix for consistency
- <SelectItem value={"delete"} className="focus:bg-destructive/[.20]"> - <div className="font-red flex text-status-red"> + <SelectItem value={"delete"} className="focus:bg-destructive/[.20]"> + <div className="font-red flex text-destructive">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx` around lines 771 - 786, The Delete SelectItem uses two different color tokens: the container div applies text-status-red while the shortcut IconComponent uses text-destructive; update one so both use the same semantic token for consistency (e.g., change the div's class or the IconComponent's class so both use text-destructive or both use text-status-red) in the SelectItem with value "delete" (look for the IconComponent instances inside that SelectItem) to ensure uniform styling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx`:
- Line 18: The JSX className currently uses a template literal with `${ping &&
"animate-pulse text-accent-emerald-foreground"}` which can yield the literal
"false" when ping is falsy; update the element in toolbarSelectItem/index.tsx
(the JSX node with className={`mr-2 mt-[0.15em] h-4 w-4 ...`}) to use the
project's cn() utility to compose classes (e.g., cn("mr-2 mt-[0.15em] h-4 w-4",
{ "animate-pulse text-accent-emerald-foreground": ping })), and add the
appropriate import for cn if missing so conditional classes are handled safely.
In
`@src/frontend/src/pages/MainPage/pages/homePage/components/McpAutoInstallContent.tsx`:
- Line 30: The banner in McpAutoInstallContent.tsx uses bg-accent-amber with
text-accent-amber-foreground which currently resolve to the same color; update
the alert's class string to use a clearly contrasting text token (for example
replace text-accent-amber-foreground with text-foreground or a dedicated
contrasting token like text-accent-amber-contrast) so the text is readable
against bg-accent-amber, or alternatively change the background to a
lighter/darker accent variant (e.g., an /emphasis or /muted accent token) to
restore contrast; if you prefer a design-system fix, adjust the
--accent-amber-foreground token value at the theme level to guarantee sufficient
contrast.
In
`@src/frontend/src/pages/MainPage/pages/knowledgePage/config/__tests__/knowledgeBaseColumns.test.tsx`:
- Around line 20-21: The FILE_ICONS mock in the test is out of sync: update the
mocked entries for pdf and txt in the FILE_ICONS mock used by the
knowledgeBaseColumns tests so their icon names match production (use "File" for
pdf and "FileType" for txt) instead of "FileText" and "FileCode", ensuring the
column renderer test exercises the same icon selection logic as the real
src/frontend/src/utils/styleUtils.ts FILE_ICONS mapping.
---
Outside diff comments:
In
`@src/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsx`:
- Around line 26-30: handleThemeChange currently accepts an untyped theme
parameter; add a TypeScript type annotation to the parameter (e.g. change the
signature of handleThemeChange to handleThemeChange(theme: ThemePreference) or
handleThemeChange(theme: 'light'|'dark'|'system') depending on your existing
types) so calls to setHasInteracted, setSelectedTheme and setThemePreference are
type-safe; import or reference the existing Theme/ThemePreference type if
available, otherwise declare the explicit union string type in this file.
---
Nitpick comments:
In
`@src/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsx`:
- Around line 52-64: Replace the inline conditional className string in the
ThemeButtons component's Button (the element rendering ForwardedIconComponent
with id/data-testid "menu_light_button") to use the cn() utility for class
composition; import cn from "@/utils/utils" (or existing utils file) and pass
the static classes ("relative z-10 inline-flex items-center rounded-full px-1")
and the conditional classes (selectedTheme === "light" ? "text-foreground" :
"text-foreground hover:bg-accent-amber-foreground hover:text-background") as
separate arguments to cn() so the conditional styling is clearer and consistent
with project conventions.
In `@src/frontend/src/components/core/jsonEditor/index.tsx`:
- Around line 395-398: The className conditional uses the token
"bg-accent-emerald-foreground" for the success background; change it to the
background token "bg-accent-emerald" where showSuccess is applied so the button
uses the intended background color (update the className expression that calls
cn with showSuccess, referencing the same cn utility and the showSuccess boolean
in this component).
In `@src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx`:
- Around line 771-786: The Delete SelectItem uses two different color tokens:
the container div applies text-status-red while the shortcut IconComponent uses
text-destructive; update one so both use the same semantic token for consistency
(e.g., change the div's class or the IconComponent's class so both use
text-destructive or both use text-status-red) in the SelectItem with value
"delete" (look for the IconComponent instances inside that SelectItem) to ensure
uniform styling.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 40dda7bb-a4d2-4e6b-a1b0-6c19db81462d
📒 Files selected for processing (33)
src/frontend/src/CustomNodes/GenericNode/components/ListSelectionComponent/ListItem.tsxsrc/frontend/src/CustomNodes/GenericNode/components/ListSelectionComponent/index.tsxsrc/frontend/src/CustomNodes/NoteNode/__tests__/color-picker-buttons.test.tsxsrc/frontend/src/CustomNodes/NoteNode/components/color-picker-buttons.tsxsrc/frontend/src/CustomNodes/NoteNode/components/select-items.tsxsrc/frontend/src/components/common/animatedNumbers/index.tsxsrc/frontend/src/components/core/appHeaderComponent/components/ThemeButtons/index.tsxsrc/frontend/src/components/core/appHeaderComponent/index.tsxsrc/frontend/src/components/core/border-trail.tsxsrc/frontend/src/components/core/chatComponents/ContentBlockDisplay.tsxsrc/frontend/src/components/core/chatComponents/ContentDisplay.tsxsrc/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/add-folder-button.tsxsrc/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/upload-folder-button.tsxsrc/frontend/src/components/core/jsonEditor/index.tsxsrc/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/components/__tests__/chat-message.test.tsxsrc/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/components/bot-message.tsxsrc/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/components/thinking-message.tsxsrc/frontend/src/customization/components/custom-parameter.tsxsrc/frontend/src/modals/IOModal/components/IOFieldView/components/session-selector.tsxsrc/frontend/src/modals/addMcpServerModal/index.tsxsrc/frontend/src/modals/apiModal/index.tsxsrc/frontend/src/modals/codeAreaModal/index.tsxsrc/frontend/src/modals/fileManagerModal/components/dragFilesComponent/index.tsxsrc/frontend/src/modals/modelProviderModal/components/ProviderConfigurationForm.tsxsrc/frontend/src/modals/saveChangesModal/index.tsxsrc/frontend/src/modals/templatesModal/components/TemplateGetStartedCardComponent/index.tsxsrc/frontend/src/pages/FlowPage/components/SelectionMenuComponent/index.tsxsrc/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsxsrc/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsxsrc/frontend/src/pages/MainPage/pages/homePage/components/McpAutoInstallContent.tsxsrc/frontend/src/pages/MainPage/pages/knowledgePage/config/__tests__/knowledgeBaseColumns.test.tsxsrc/frontend/src/pages/MainPage/pages/knowledgePage/config/statusConfig.tssrc/frontend/src/style/applies.css
| <ForwardedIconComponent | ||
| name={icon} | ||
| className={`mr-2 mt-[0.15em] h-4 w-4 ${ping && "animate-pulse text-green-500"}`} | ||
| className={`mr-2 mt-[0.15em] h-4 w-4 ${ping && "animate-pulse text-accent-emerald-foreground"}`} |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
JavaScript template literal ${false} interpolation behavior and best practice for conditional React className composition with Tailwind CSS
💡 Result:
1) Why `${false}` becomes "false" (and why that matters in className)
In a template literal, each ${…} expression is string-coerced (effectively via ToString/String(...)). So false becomes the string "false" — meaning patterns like:
`btn ${isActive && "btn-active"}`will produce "btn false" when isActive is false. (developer.mozilla.org)
2) Best practice: don’t use && inside template literals for classes
Prefer a class-joining helper that drops falsy values, like clsx (or classnames):
import { clsx } from "clsx";
<button className={clsx("btn", isActive && "btn-active")} />clsx explicitly discards falsy values (and even standalone booleans), so you won’t accidentally render "false" as a class token. (npmjs.com)
3) Tailwind-specific best practice: don’t dynamically construct partial class names
Tailwind scans your source as text and can’t understand string interpolation like bg-${color}-600; it recommends mapping to complete, static class strings instead:
const variants = {
blue: "bg-blue-600 hover:bg-blue-500",
red: "bg-red-600 hover:bg-red-500",
} as const;
<button className={clsx("rounded px-2 py-1", variants[color])} />This keeps class names statically detectable. (tailwindcss.com)
4) Common “best of both worlds” setup (Tailwind + React)
Many codebases wrap clsx with tailwind-merge so conflicting utilities resolve predictably:
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}Then:
<div className={cn("p-2 text-sm", isActive && "text-lg", className)} />Citations:
- 1: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean/tostring?utm_source=openai
- 2: https://www.npmjs.com/package/clsx?utm_source=openai
- 3: https://tailwindcss.com/docs/content-configuration
- 4: https://infinum.com/handbook/frontend/react/tailwind/best-practices?utm_source=openai
🏁 Script executed:
# Verify the exact code in the file
cat -n src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx | head -30Repository: langflow-ai/langflow
Length of output: 1194
Use cn() utility to compose conditional Tailwind classes instead of template literals with && operator.
Line 18 uses ${ping && "animate-pulse text-accent-emerald-foreground"} in a template literal. When ping is falsy, this produces the literal string "false" as a class, which should be avoided. Apply the cn() utility function (per project guidelines) to safely handle conditional classes:
Proposed fix
+import { cn } from "../../../../utils/cn";
+
export default function ToolbarSelectItem({
value,
icon,
style,
dataTestId,
ping,
shortcut,
}: toolbarSelectItemProps) {
const fixedShortcut = shortcut?.split("+");
return (
<div className={`flex ${style}`} data-testid={dataTestId}>
<ForwardedIconComponent
name={icon}
- className={`mr-2 mt-[0.15em] h-4 w-4 ${ping && "animate-pulse text-accent-emerald-foreground"}`}
+ className={cn("mr-2 mt-[0.15em] h-4 w-4", ping && "animate-pulse text-accent-emerald-foreground")}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| className={`mr-2 mt-[0.15em] h-4 w-4 ${ping && "animate-pulse text-accent-emerald-foreground"}`} | |
| import { cn } from "../../../../utils/cn"; | |
| export default function ToolbarSelectItem({ | |
| value, | |
| icon, | |
| style, | |
| dataTestId, | |
| ping, | |
| shortcut, | |
| }: toolbarSelectItemProps) { | |
| const fixedShortcut = shortcut?.split("+"); | |
| return ( | |
| <div className={`flex ${style}`} data-testid={dataTestId}> | |
| <ForwardedIconComponent | |
| name={icon} | |
| className={cn("mr-2 mt-[0.15em] h-4 w-4", ping && "animate-pulse text-accent-emerald-foreground")} | |
| /> | |
| </div> | |
| ); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx`
at line 18, The JSX className currently uses a template literal with `${ping &&
"animate-pulse text-accent-emerald-foreground"}` which can yield the literal
"false" when ping is falsy; update the element in toolbarSelectItem/index.tsx
(the JSX node with className={`mr-2 mt-[0.15em] h-4 w-4 ...`}) to use the
project's cn() utility to compose classes (e.g., cn("mr-2 mt-[0.15em] h-4 w-4",
{ "animate-pulse text-accent-emerald-foreground": ping })), and add the
appropriate import for cn if missing so conditional classes are handled safely.
| <div className="flex flex-col gap-1 mt-4"> | ||
| {!isLocalConnection && ( | ||
| <div className="mb-2 rounded-md bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:bg-amber-950 dark:text-amber-200"> | ||
| <div className="mb-2 rounded-md bg-accent-amber px-3 py-2 text-sm text-accent-amber-foreground"> |
There was a problem hiding this comment.
Potential contrast regression in the alert banner (text and background may be identical).
At Line 30, bg-accent-amber is paired with text-accent-amber-foreground, but current token values indicate both amber vars resolve to the same HSL in light theme. This can make the warning text unreadable.
Suggested fix
- <div className="mb-2 rounded-md bg-accent-amber px-3 py-2 text-sm text-accent-amber-foreground">
+ <div className="mb-2 rounded-md bg-accent-amber/15 px-3 py-2 text-sm text-accent-amber-foreground">If the filled amber background is desired, the better fix is at token level (set --accent-amber-foreground to a contrasting value).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div className="mb-2 rounded-md bg-accent-amber px-3 py-2 text-sm text-accent-amber-foreground"> | |
| <div className="mb-2 rounded-md bg-accent-amber/15 px-3 py-2 text-sm text-accent-amber-foreground"> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/frontend/src/pages/MainPage/pages/homePage/components/McpAutoInstallContent.tsx`
at line 30, The banner in McpAutoInstallContent.tsx uses bg-accent-amber with
text-accent-amber-foreground which currently resolve to the same color; update
the alert's class string to use a clearly contrasting text token (for example
replace text-accent-amber-foreground with text-foreground or a dedicated
contrasting token like text-accent-amber-contrast) so the text is readable
against bg-accent-amber, or alternatively change the background to a
lighter/darker accent variant (e.g., an /emphasis or /muted accent token) to
restore contrast; if you prefer a design-system fix, adjust the
--accent-amber-foreground token value at the theme level to guarantee sufficient
contrast.
| pdf: { icon: "FileText", color: "text-datatype-red dark:text-datatype-red-foreground" }, | ||
| txt: { icon: "FileCode", color: "text-datatype-purple dark:text-datatype-purple-foreground" }, |
There was a problem hiding this comment.
Fix FILE_ICONS mock drift for pdf and txt icons
On Line 20 and Line 21, the mocked icon names (FileText, FileCode) don’t match the production FILE_ICONS mapping in src/frontend/src/utils/styleUtils.ts (File, FileType). This can mask icon-selection regressions in the column renderer tests.
Suggested patch
jest.mock("@/utils/styleUtils", () => ({
FILE_ICONS: {
- pdf: { icon: "FileText", color: "text-datatype-red dark:text-datatype-red-foreground" },
- txt: { icon: "FileCode", color: "text-datatype-purple dark:text-datatype-purple-foreground" },
+ pdf: { icon: "File", color: "text-datatype-red dark:text-datatype-red-foreground" },
+ txt: { icon: "FileType", color: "text-datatype-purple dark:text-datatype-purple-foreground" },
},
}));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pdf: { icon: "FileText", color: "text-datatype-red dark:text-datatype-red-foreground" }, | |
| txt: { icon: "FileCode", color: "text-datatype-purple dark:text-datatype-purple-foreground" }, | |
| pdf: { icon: "File", color: "text-datatype-red dark:text-datatype-red-foreground" }, | |
| txt: { icon: "FileType", color: "text-datatype-purple dark:text-datatype-purple-foreground" }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/frontend/src/pages/MainPage/pages/knowledgePage/config/__tests__/knowledgeBaseColumns.test.tsx`
around lines 20 - 21, The FILE_ICONS mock in the test is out of sync: update the
mocked entries for pdf and txt in the FILE_ICONS mock used by the
knowledgeBaseColumns tests so their icon names match production (use "File" for
pdf and "FileType" for txt) instead of "FileText" and "FileCode", ensuring the
column renderer test exercises the same icon selection logic as the real
src/frontend/src/utils/styleUtils.ts FILE_ICONS mapping.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #12033 +/- ##
=======================================
Coverage 37.45% 37.46%
=======================================
Files 1616 1616
Lines 79041 79041
Branches 11945 11945
=======================================
+ Hits 29606 29611 +5
+ Misses 47777 47772 -5
Partials 1658 1658
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Objective
Improve theme consistency by replacing hardcoded Tailwind color utilities with project-defined design tokens across 33 frontend files.
Changes
text-accent-red-foreground, text-status-yellow tokens
Summary by CodeRabbit