Skip to content

Conversation

@kyrers
Copy link

@kyrers kyrers commented Oct 23, 2025

Resolves #88.


PR-Codex overview

This PR focuses on refactoring the codebase to remove styled-components in favor of utility-first CSS with Tailwind CSS. It also introduces a new ThemeProvider and updates various components to enhance consistency and maintainability.

Detailed summary

  • Removed styled-components and related styles.
  • Added tailwindcss support in vite.config.js.
  • Implemented ThemeProvider for theming.
  • Updated Overlay, Logo, and various form components to use Tailwind CSS classes.
  • Simplified component structures and props.
  • Removed unused theme imports and related code.
  • Updated styles in multiple components to use utility classes.

The following files were skipped due to too many changes: yarn.lock

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Chores

    • Upgraded UI components library and added Tailwind tooling; removed styled-components, react-modal, and related typings.
  • Refactor

    • Replaced CSS-in-JS theming with a CSS-based ThemeProvider and new global stylesheet.
    • Migrated components and layout from CSS-in-JS to utility/class-based (Tailwind) styling, removing legacy styled helpers and global styled styles.

@kyrers kyrers self-assigned this Oct 23, 2025
@netlify
Copy link

netlify bot commented Oct 23, 2025

Deploy Preview for curate-v2 failed. Why did it fail? →

Name Link
🔨 Latest commit bb0901b
🔍 Latest deploy log https://app.netlify.com/projects/curate-v2/deploys/6903eec0d863880008f34537

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 23, 2025

Walkthrough

Migrates styling from styled-components to Tailwind: upgrades @kleros/ui-components-library to v3.6.0, removes styled-components/react-modal and related type packages, adds Tailwind tooling and global CSS, replaces the styled ThemeProvider with a document-class-based ThemeProvider, and converts many components from CSS-in-JS to utility/class-based styling.

Changes

Cohort / File(s) Change Summary
Dependencies & Build
web/package.json, web/vite.config.js
Bumped @kleros/ui-components-library ^2.20.0 → ^3.6.0; removed styled-components, react-modal, and related @types/*; added tailwindcss & @tailwindcss/vite ^4.1.16; registered Tailwind plugin in Vite.
App root / Provider swap
web/src/app.tsx
Replaced StyledComponentsProvider import/usage with new ThemeProvider and added ./global.css import.
New Theme provider
web/src/context/ThemeProvider.tsx
Added ThemeProvider using localStorage-backed theme state, toggleTheme, and applying/removing "dark" class on document.documentElement.
Removed styled-components provider
web/src/context/StyledComponentsProvider.tsx (deleted)
Deleted previous styled-components ThemeProvider (theme objects, GlobalStyle, toggle logic).
Global CSS (Tailwind + tokens)
web/src/global.css (new)
Added global stylesheet importing UI library theme & Tailwind, defining CSS variables, dark-mode overrides, typography/reset, toast/skeleton/scrollbar, and other tokens.
Removed styled helpers & themes
web/src/styles/*
web/src/styles/commonStyles.ts, customScrollbar.ts, global-style.ts, landscapeStyle.ts, themes.ts
Removed styled-components helpers, global styled GlobalStyle, landscape helpers, custom scrollbar, and exported lightTheme/darkTheme.
Type declarations
web/global.d.ts
Removed styled-components DefaultTheme augmentation; converted to module (export {}) while keeping asset module declarations.
Web3 provider color
web/src/context/Web3Provider.tsx
Replaced import-based theme color with hardcoded #4D00B4 in themeVariables.
Layout & components → utility classes
Multiple files (e.g., web/src/layout/index.tsx, web/src/layout/Header/**, web/src/components/**, web/src/layout/Header/navbar/**, web/src/components/Overlay*.tsx, web/src/components/InfoCard.tsx, web/src/components/LightButton.tsx, ...)
Replaced many styled-components wrappers and styled exports with plain JSX using Tailwind-like className strings; preserved component APIs and behavior while moving styling to global.css/classes.
Modal setup removed
web/src/index.tsx
Removed react-modal import and Modal.setAppElement(container) call.

Sequence Diagram(s)

sequenceDiagram
    participant App as App.tsx
    participant ThemeProv as ThemeProvider
    participant ToggleCtx as ToggleThemeProvider
    participant Document as document.documentElement

    App->>ThemeProv: render children inside <ThemeProvider>
    ThemeProv->>ThemeProv: read theme from localStorage (default "dark")
    ThemeProv->>ToggleCtx: provide { theme, toggleTheme }
    ThemeProv->>Document: add/remove "dark" class (useEffect) on theme change

    Note right of ThemeProv #eef2ff: toggleTheme updates state → persist to localStorage\nand updates document.classList
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Files needing extra attention:
    • web/src/global.css — large CSS surface, dark-mode tokens, and interactions with the UI library's imported theme.
    • web/src/context/ThemeProvider.tsx — DOM side-effect (document.classList) and persistence logic.
    • web/vite.config.js & web/package.json — Tailwind plugin and dependency changes affecting build.
    • Deleted theme/style modules (web/src/styles/*, global.d.ts) — verify no remaining imports expect styled-components theme types.
    • Broad component refactors to utility classes — quick spot-check rendering and responsive behavior.

Possibly related issues

Possibly related PRs

Suggested labels

Type: Enhancement :sparkles:, Package: Web

Suggested reviewers

  • kemuru
  • Harman-singh-waraich
  • alcercu

Poem

🐰 Hop hop, a tailwind breeze,
Out with styled-components, in with ease.
Themes now dance upon the document's crown,
Variables hum as old styles come down.
A rabbit cheers — light code, nimble and sound.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "chore: migrate from styled components to tailwind" is concise, clear, and directly related to the primary objective of the changeset. It accurately captures the main migration effort without unnecessary detail or vague terminology. The title appropriately reflects that this is a maintenance/chore change involving a technology migration from styled-components to Tailwind CSS, which aligns with the extensive refactoring evidenced in the raw summary across multiple files, components, and configuration changes.
Linked Issues Check ✅ Passed The code changes comprehensively address all primary objectives from linked issue #88. The PR successfully upgrades @kleros/ui-components-library to v3 [package.json], removes all styled-components usage and dependencies throughout the codebase, and introduces Tailwind CSS integration including a new ThemeProvider for theme management [ThemeProvider.tsx, global.css, vite.config.js]. All styled-components-based styling in components (AccountDisplay, InfoCard, LightButton, Header components, Layout components, etc.) has been replaced with Tailwind-based utility classes, and theme management now uses CSS variables and the "dark" class strategy compatible with Tailwind's approach [multiple component files].
Out of Scope Changes Check ✅ Passed All changes in this pull request are directly related to the stated migration objectives from issue #88. The modifications span dependency updates (package.json), removal of styled-components infrastructure (StyledComponentsProvider.tsx, global-style.ts, themes.ts, customScrollbar.ts, landscapeStyle.ts), introduction of Tailwind infrastructure (global.css, ThemeProvider.tsx, vite.config.js updates), and systematic migration of all component and layout files to use Tailwind classes instead of styled-components. No unrelated features, bug fixes, or architectural changes are present outside the scope of the styled-components to Tailwind migration.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/migrate-from-styled-components-to-tailwind

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
web/src/global.css (1)

60-62: Consider reducing !important usage.

The !important declarations on lines 61 and 147 override library defaults for ReactModal and Toastify. While sometimes necessary for third-party library overrides, consider if these can be achieved through higher CSS specificity instead.

If the library CSS is loaded before your global styles, you may be able to increase specificity without !important:

/* Instead of: */
.ReactModal__Overlay {
  background-color: #1b003fcc !important;
}

/* Try: */
.ReactModal__Overlay.ReactModal__Overlay {
  background-color: #1b003fcc;
}

Also applies to: 145-148

web/src/context/ThemeProvider.tsx (1)

8-8: Improve type safety for theme values.

The theme is currently typed as string, which allows any string value. This should be constrained to the valid theme values for better type safety and developer experience.

Apply this diff to add proper typing:

+type Theme = "light" | "dark";
+
 const ThemeProvider: React.FC<{
   children: React.ReactNode;
 }> = ({ children }) => {
-  const [theme, setTheme] = useLocalStorage<string>("theme", "dark");
+  const [theme, setTheme] = useLocalStorage<Theme>("theme", "dark");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc5502a and ad2c61b.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (11)
  • web/package.json (2 hunks)
  • web/src/app.tsx (3 hunks)
  • web/src/context/StyledComponentsProvider.tsx (0 hunks)
  • web/src/context/ThemeProvider.tsx (1 hunks)
  • web/src/global.css (1 hunks)
  • web/src/styles/commonStyles.ts (0 hunks)
  • web/src/styles/customScrollbar.ts (0 hunks)
  • web/src/styles/global-style.ts (0 hunks)
  • web/src/styles/landscapeStyle.ts (0 hunks)
  • web/src/styles/themes.ts (0 hunks)
  • web/vite.config.js (2 hunks)
💤 Files with no reviewable changes (6)
  • web/src/styles/global-style.ts
  • web/src/styles/landscapeStyle.ts
  • web/src/styles/themes.ts
  • web/src/styles/commonStyles.ts
  • web/src/styles/customScrollbar.ts
  • web/src/context/StyledComponentsProvider.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Redirect rules - curate-v2
  • GitHub Check: Header rules - curate-v2
  • GitHub Check: Pages changed - curate-v2
🔇 Additional comments (6)
web/vite.config.js (1)

5-5: LGTM! Tailwind v4 Vite integration is correct.

The Tailwind CSS integration follows the standard pattern for v4 with Vite using the @tailwindcss/vite plugin.

Also applies to: 32-32

web/src/global.css (1)

1-20: LGTM! Tailwind v4 @theme directive and imports are correctly structured.

The global CSS setup follows Tailwind v4 best practices: importing the UI library theme, importing Tailwind, and defining custom design tokens via the @theme directive. The token definitions are comprehensive and well-organized.

web/package.json (2)

78-78: LGTM! Tailwind CSS dependencies are correctly added.

Both tailwindcss and @tailwindcss/vite are on the same version (4.1.16), which ensures consistency. The @tailwindcss/vite package is appropriately placed in both dependencies and devDependencies for build tooling access.

Also applies to: 107-107


73-73: Manually verify component compatibility after Tailwind migration to v3.6.0.

The upgrade to v3.6.0 involved a major migration from styled-components to Tailwind CSS. The library was migrated to Tailwind CSS, which includes changes to component styling and theming. Tailwind is already configured in the project (v4.1.16).

The codebase uses 23+ components from the library across 40+ files, including several internal components prefixed with underscore (_TimelineItem1, _IItem1). However, no public changelog documents specific breaking changes and component API modifications for v3.6.0.

Actions required:

  • Test all component usages throughout the application (run tests and manual QA)
  • Verify visual regressions from CSS token/spacing changes
  • Confirm internal components (_TimelineItem1, _IItem1) remain stable and exported in v3
  • Check for any prop renames or removed component APIs against the library's Storybook or GitHub repository
web/src/context/ThemeProvider.tsx (1)

10-22: LGTM! Dark mode implementation is correct.

The theme toggling logic and the useEffect that applies the dark class to document.documentElement correctly implements Tailwind's class-based dark mode strategy. The implementation will work seamlessly with Tailwind's dark: variant.

web/src/app.tsx (1)

4-4: LGTM! Theme provider migration is correctly implemented.

The migration from StyledComponentsProvider to the new ThemeProvider is clean and correct. The global.css import is properly placed early in the file, and the ThemeProvider correctly wraps the entire application as the outermost provider to ensure theme context is available throughout the component tree.

Also applies to: 7-7, 26-26, 59-59

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
web/src/context/Web3Provider.tsx (1)

62-62: Consider adding the brand color to the theme system for maintainability.

The hardcoded color #4D00B4 is correct—it matches the primary brand color used throughout SVG assets. However, since the codebase has migrated to Tailwind with a theme system (defined in web/src/global.css), consider adding this color to the @theme block for consistency and easier maintenance:

/* In web/src/global.css @theme block */
--color-primary: #4D00B4;

Then reference it in Web3Provider:

"--w3m-color-mix": "var(--color-primary)",

This keeps brand colors centralized and easier to maintain across the codebase. The color itself doesn't need to change between light/dark modes—this is a brand constant, not a theme-dependent color.

web/src/layout/index.tsx (1)

22-22: Consider extracting the hardcoded spacing value.

The hardcoded pt-[70px] value appears to offset the ToastContainer from the header. For better maintainability and theme consistency, consider defining this as a CSS variable or Tailwind theme extension that matches the header height.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad2c61b and d2d2579.

📒 Files selected for processing (3)
  • web/global.d.ts (1 hunks)
  • web/src/context/Web3Provider.tsx (1 hunks)
  • web/src/layout/index.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Redirect rules - curate-v2
  • GitHub Check: Header rules - curate-v2
  • GitHub Check: Pages changed - curate-v2
🔇 Additional comments (2)
web/src/layout/index.tsx (1)

23-23: Consider adding dark mode variant.

The background class bg-klerosUIComponentsLightBackground implies a light theme background. Based on the PR's ThemeProvider that toggles a document-level dark class, consider whether this element needs a corresponding dark mode variant (e.g., dark:bg-klerosUIComponentsDarkBackground).

web/global.d.ts (1)

1-12: LGTM!

The removal of styled-components module augmentation is appropriate for the Tailwind migration. The file correctly preserves the necessary ambient declarations for SVG and PNG imports while maintaining proper module structure with the export {} statement.

@kleros kleros deleted a comment from coderabbitai bot Oct 24, 2025
@kleros kleros deleted a comment from coderabbitai bot Oct 24, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 30, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

🧹 Nitpick comments (3)
web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/FormContact.tsx (1)

45-45: Consider using standard spacing scale instead of arbitrary value.

The arbitrary value mb-[10px] works correctly in Tailwind v4, but using the standard spacing scale improves consistency across the codebase. Since 10px equals 2.5rem (2.5 × 4px), consider using mb-2.5 instead.

-      <label className="flex justify-between mb-[10px]">{contactLabel}</label>
+      <label className="flex justify-between mb-2.5">{contactLabel}</label>
web/src/layout/Header/Logo.tsx (2)

8-13: Remove unnecessary whitespace literal.

The {" "} on line 9 serves no purpose and can be removed for cleaner code.

Apply this diff:

  <div className="flex flex-row items-center gap-4">
-    {" "}
    <Link to={"/"}>
      <CurateLogo className="transition duration-100 max-h-12 w-auto hover:fill-white/75" />
    </Link>
  </div>

10-12: Add accessible label for the logo link.

The logo link lacks descriptive text for screen readers. Add an aria-label to improve accessibility.

Apply this diff:

-    <Link to={"/"}>
+    <Link to={"/"} aria-label="Home">
      <CurateLogo className="transition duration-100 max-h-12 w-auto hover:fill-white/75" />
    </Link>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f638cb8 and bb0901b.

📒 Files selected for processing (23)
  • web/src/app.tsx (3 hunks)
  • web/src/components/ConnectWallet/AccountDisplay.tsx (2 hunks)
  • web/src/components/InfoCard.tsx (1 hunks)
  • web/src/components/LightButton.tsx (1 hunks)
  • web/src/components/Overlay.tsx (1 hunks)
  • web/src/components/OverlayPortal.tsx (1 hunks)
  • web/src/context/ThemeProvider.tsx (1 hunks)
  • web/src/global.css (1 hunks)
  • web/src/layout/Header/DesktopHeader.tsx (1 hunks)
  • web/src/layout/Header/Logo.tsx (1 hunks)
  • web/src/layout/Header/index.tsx (1 hunks)
  • web/src/layout/Header/navbar/DappList.tsx (1 hunks)
  • web/src/layout/Header/navbar/Debug.tsx (2 hunks)
  • web/src/layout/Header/navbar/Explore.tsx (2 hunks)
  • web/src/layout/Header/navbar/Menu/Help.tsx (1 hunks)
  • web/src/layout/Header/navbar/Menu/Settings/General.tsx (1 hunks)
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx (1 hunks)
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/FormContact.tsx (1 hunks)
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx (3 hunks)
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx (1 hunks)
  • web/src/layout/Header/navbar/Menu/Settings/index.tsx (1 hunks)
  • web/src/layout/Header/navbar/Menu/index.tsx (1 hunks)
  • web/src/layout/Header/navbar/Product.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/src/context/ThemeProvider.tsx
  • web/src/app.tsx
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: kyrers
Repo: kleros/curate-v2 PR: 89
File: web/src/layout/index.tsx:15-28
Timestamp: 2025-10-24T21:25:59.174Z
Learning: In Tailwind v4, when using CSS variables from external libraries like kleros/ui-components-library, add the `source` directive in global.css to tell Tailwind to scan and generate utility classes from those variables. Example: `source "../node_modules/kleros/ui-components-library";`
📚 Learning: 2024-11-04T13:31:54.080Z
Learnt from: Harman-singh-waraich
Repo: kleros/curate-v2 PR: 65
File: web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx:72-96
Timestamp: 2024-11-04T13:31:54.080Z
Learning: In the React TypeScript component `FormContactDetails` in `web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx`, error handling and user feedback are implemented within the `addUser` and `updateEmail` functions, which display toasts to the user.

Applied to files:

  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/FormContact.tsx
  • web/src/layout/Header/navbar/Menu/Settings/index.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx
📚 Learning: 2024-11-04T13:41:31.226Z
Learnt from: Harman-singh-waraich
Repo: kleros/curate-v2 PR: 65
File: web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx:126-126
Timestamp: 2024-11-04T13:41:31.226Z
Learning: In `web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx`, the `isUndefined` function effectively handles `null` or `undefined` values. Therefore, using the non-null assertion `!` on `user?.emailUpdateableAt` when calling `timeLeftUntil(user?.emailUpdateableAt!)` is acceptable, as potential `null` or `undefined` cases are already managed.

Applied to files:

  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/FormContact.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx
📚 Learning: 2024-11-04T13:33:39.755Z
Learnt from: Harman-singh-waraich
Repo: kleros/curate-v2 PR: 65
File: web/src/pages/Settings/index.tsx:18-26
Timestamp: 2024-11-04T13:33:39.755Z
Learning: In `web/src/pages/Settings/index.tsx`, the parent route handles the default `/settings` route, error boundaries, and loading states, so it's not necessary to include them in this component.

Applied to files:

  • web/src/layout/Header/navbar/Menu/Settings/index.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx
📚 Learning: 2024-11-04T13:39:19.748Z
Learnt from: Harman-singh-waraich
Repo: kleros/curate-v2 PR: 65
File: web/src/utils/atlas/updateEmail.ts:21-38
Timestamp: 2024-11-04T13:39:19.748Z
Learning: For the `updateEmail` function in `web/src/utils/atlas/updateEmail.ts`, input validation and error handling are performed in the component that utilizes it. Therefore, additional checks within this utility function are unnecessary.

Applied to files:

  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx
📚 Learning: 2024-11-04T13:34:45.425Z
Learnt from: Harman-singh-waraich
Repo: kleros/curate-v2 PR: 65
File: web/src/utils/atlas/confirmEmail.ts:24-36
Timestamp: 2024-11-04T13:34:45.425Z
Learning: In the `confirmEmail` function in `web/src/utils/atlas/confirmEmail.ts`, input validation for the address is performed in the calling component, and additional checks are done in the API call itself. Input validation does not need to be repeated in this function.

Applied to files:

  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx
📚 Learning: 2024-11-04T13:29:55.971Z
Learnt from: Harman-singh-waraich
Repo: kleros/curate-v2 PR: 65
File: web/src/context/AtlasProvider.tsx:176-193
Timestamp: 2024-11-04T13:29:55.971Z
Learning: In the `web/src/context/AtlasProvider.tsx` file of the React application, the `authoriseUser` function handles session invalidation and delegates error handling and user notifications to the functions that invoke it. Therefore, adding error notifications within `authoriseUser` is unnecessary.

Applied to files:

  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx
  • web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx
📚 Learning: 2025-10-24T21:25:59.174Z
Learnt from: kyrers
Repo: kleros/curate-v2 PR: 89
File: web/src/layout/index.tsx:15-28
Timestamp: 2025-10-24T21:25:59.174Z
Learning: In Tailwind v4, when using CSS variables from external libraries like kleros/ui-components-library, add the `source` directive in global.css to tell Tailwind to scan and generate utility classes from those variables. Example: `source "../node_modules/kleros/ui-components-library";`

Applied to files:

  • web/src/global.css
🧬 Code graph analysis (5)
web/src/layout/Header/navbar/Debug.tsx (1)
web/src/consts/index.ts (2)
  • RELEASE_VERSION (12-12)
  • GIT_URL (11-11)
web/src/layout/Header/navbar/Menu/Settings/General.tsx (2)
web/src/components/EnsureChain.tsx (1)
  • EnsureChain (10-14)
web/src/components/ConnectWallet/AccountDisplay.tsx (3)
  • IdenticonOrAvatar (16-34)
  • AddressOrName (40-50)
  • ChainDisplay (52-56)
web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx (2)
web/src/layout/Header/navbar/index.tsx (1)
  • ISettings (54-56)
web/src/components/EnsureChain.tsx (1)
  • EnsureChain (10-14)
web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx (1)
web/src/utils/date.ts (1)
  • timeLeftUntil (43-69)
web/src/layout/Header/index.tsx (1)
web/src/utils/getGraphqlUrl.ts (1)
  • getGraphqlUrl (3-7)
🔇 Additional comments (12)
web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/FormContact.tsx (1)

45-52: Migration looks clean, but verify label-input association for accessibility.

The migration from styled-components to Tailwind classes is well-executed. However, the <label> on line 45 lacks a htmlFor attribute to associate it with the input field. If the Field component renders an input element, ensure proper label-input association for accessibility.

Consider adding a htmlFor attribute if the Field component exposes an id:

-      <label className="flex justify-between mb-[10px]">{contactLabel}</label>
+      <label htmlFor="contact-input" className="flex justify-between mb-[10px]">{contactLabel}</label>
       <Field
         className="flex flex-col items-center w-full"
+        id="contact-input"
         variant={fieldVariant}

Alternatively, if the Field component from @kleros/ui-components-library handles accessibility internally or doesn't support id props, you may disregard this suggestion.

web/src/layout/Header/navbar/DappList.tsx (1)

98-98: LGTM!

The h1 header uses standard Tailwind utility classes correctly.

web/src/layout/Header/navbar/Menu/Help.tsx (1)

52-53: The breakpoint is already properly configured—no action needed.

The custom landscape-900: breakpoint is correctly defined in web/src/global.css using Tailwind v4's @theme block with the --breakpoint-landscape-900: 900px; variable, which automatically creates the responsive modifier. The review comment incorrectly assumes traditional Tailwind configuration (JS/TS config file), which is not applicable to Tailwind v4's CSS-first approach. The code at lines 52-53 in Help.tsx correctly uses this pre-configured breakpoint.

Likely an incorrect or invalid review comment.

web/src/layout/Header/navbar/Debug.tsx (1)

5-20: LGTM!

The migration from styled-components to className-based styling is implemented correctly. The arbitrary font-family syntax font-[Roboto_Mono,monospace] is proper Tailwind v4 usage.

web/src/components/Overlay.tsx (1)

1-5: LGTM!

Clean conversion from styled-component to a functional component with Tailwind classes. The bg-black-low-opacity custom color should be defined in your theme configuration.

web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsx (1)

36-49: LGTM!

Successful migration from styled-components to utility classes. The SVG fill and layout classes are properly applied.

web/src/global.css (2)

1-67: Well-structured Tailwind v4 integration.

The global stylesheet properly:

  • Imports the UI library theme and Tailwind v4 using the new @import syntax
  • Defines custom theme tokens via @theme directive
  • Implements accessible focus management with :focus-visible (addressing the previous review concern)

The focus styling (lines 60-67) now correctly preserves keyboard navigation accessibility while removing focus outlines for mouse users.


138-142: Verify browser support for CSS nesting.

The nested selector syntax ul { li { ... } } requires modern browsers. Based on your Tailwind v4 adoption (which targets Chrome 111+, Safari 16.4+, Firefox 128+), this should be supported, but confirm this aligns with your browser compatibility requirements.

web/src/layout/Header/index.tsx (1)

12-33: LGTM! Clean migration to Tailwind v4 syntax.

The header structure correctly uses Tailwind v4 features including advanced selector syntax for StatusBanner styling and CSS variables for theme integration. The sticky positioning and backdrop blur effects are properly configured.

web/src/layout/Header/navbar/Menu/Settings/General.tsx (1)

20-49: LGTM! Proper use of Tailwind v4 advanced features.

The component correctly uses Tailwind v4's advanced selector syntax ([&>label], [&_label]) and pseudo-element utilities (before:content-['']) to style nested elements. The layout structure is clean and maintains the original functionality.

web/src/layout/Header/DesktopHeader.tsx (1)

43-43: LGTM! Correct Tailwind v4 important modifier syntax.

The important modifier is correctly placed at the end of the utility class (fill-white!), which is the proper Tailwind v4 syntax.

web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx (1)

18-30: LGTM!

The migration to Tailwind utilities is well-executed. The flexbox layout structure correctly preserves the component's intended design with proper centering and spacing.

Comment on lines +60 to +75
<div
className={
"flex flex-col justify-between h-auto items-center gap-2 bg-klerosUIComponentsWhiteBackground p-0 cursor-pointer" +
"hover:[&_label]:text-white hover:[&_label]:transition-colors hover:[&_label]:duration-200 landscape-900:hover:bg-white-low-opacity-strong landscape-900:hover:transition-[background-color_0.1s]" +
"landscape-900:bg-white-low-opacity-subtle landscape-900:flex-row landscape-900:content-center landscape-900:rounded-[300px] landscape-900:gap-0 landscape-900:py-0 landscape-900:px-3"
}
>
<div
className={
"flex items-center gap-2 w-fit min-h-8 [&>label]:text-base [&>label]:font-semibold" +
"landscape-900:gap-3 landscape-900:[&>label]:text-sm landscape-900:[&>label]:font-normal"
}
>
<IdenticonOrAvatar size="32" />
<AddressOrName />
</AccountContainer>
<ChainConnectionContainer>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix missing spaces in className concatenation.

When concatenating string literals with +, spaces between class names are lost, causing classes to merge incorrectly (e.g., cursor-pointer + "hover:... becomes cursor-pointerhover:).

Apply this diff to add spaces at the end of each segment:

     <div
       className={
-        "flex flex-col justify-between h-auto items-center gap-2 bg-klerosUIComponentsWhiteBackground p-0 cursor-pointer" +
-        "hover:[&_label]:text-white hover:[&_label]:transition-colors hover:[&_label]:duration-200 landscape-900:hover:bg-white-low-opacity-strong landscape-900:hover:transition-[background-color_0.1s]" +
-        "landscape-900:bg-white-low-opacity-subtle landscape-900:flex-row landscape-900:content-center landscape-900:rounded-[300px] landscape-900:gap-0 landscape-900:py-0 landscape-900:px-3"
+        "flex flex-col justify-between h-auto items-center gap-2 bg-klerosUIComponentsWhiteBackground p-0 cursor-pointer " +
+        "hover:[&_label]:text-white hover:[&_label]:transition-colors hover:[&_label]:duration-200 landscape-900:hover:bg-white-low-opacity-strong landscape-900:hover:transition-[background-color_0.1s] " +
+        "landscape-900:bg-white-low-opacity-subtle landscape-900:flex-row landscape-900:content-center landscape-900:rounded-[300px] landscape-900:gap-0 landscape-900:py-0 landscape-900:px-3"
       }
     >
       <div
         className={
-          "flex items-center gap-2 w-fit min-h-8 [&>label]:text-base [&>label]:font-semibold" +
-          "landscape-900:gap-3 landscape-900:[&>label]:text-sm landscape-900:[&>label]:font-normal"
+          "flex items-center gap-2 w-fit min-h-8 [&>label]:text-base [&>label]:font-semibold " +
+          "landscape-900:gap-3 landscape-900:[&>label]:text-sm landscape-900:[&>label]:font-normal"
         }
       >
🤖 Prompt for AI Agents
In web/src/components/ConnectWallet/AccountDisplay.tsx around lines 60 to 75,
the string literal concatenations for className are missing trailing spaces
which causes class names to merge (e.g., "cursor-pointer" + "hover:..." =>
"cursor-pointerhover:..."); fix by adding a single space at the end of each
string segment (or at the start of the next segment) so that each concatenated
piece has a separating space between class names, and apply the same change to
both the outer and inner div className concatenations.

Comment on lines +76 to +84
<div
className={
"flex w-fit min-h-8 items-center pl-0 [&>label]:text-klerosUIComponentsSuccess [&>label]:text-base [&>label]:font-medium" +
"before:content-[''] before:w-2 before:h-2 before:rounded-[50%] before:bg-klerosUIComponentsSuccess before:my-0 before:mr-[13px] before:ml-[3px]" +
"landscape-900:display-none"
}
>
<ChainDisplay />
</ChainConnectionContainer>
</Container>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix className concatenation and use hidden instead of display-none.

Two issues here:

  1. Missing spaces in string concatenation (same issue as above)
  2. display-none is not a valid Tailwind class; use hidden instead

Apply this diff:

       <div
         className={
-          "flex w-fit min-h-8 items-center pl-0 [&>label]:text-klerosUIComponentsSuccess [&>label]:text-base [&>label]:font-medium" +
-          "before:content-[''] before:w-2 before:h-2 before:rounded-[50%] before:bg-klerosUIComponentsSuccess before:my-0 before:mr-[13px] before:ml-[3px]" +
-          "landscape-900:display-none"
+          "flex w-fit min-h-8 items-center pl-0 [&>label]:text-klerosUIComponentsSuccess [&>label]:text-base [&>label]:font-medium " +
+          "before:content-[''] before:w-2 before:h-2 before:rounded-[50%] before:bg-klerosUIComponentsSuccess before:my-0 before:mr-[13px] before:ml-[3px] " +
+          "landscape-900:hidden"
         }
       >
📝 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.

Suggested change
<div
className={
"flex w-fit min-h-8 items-center pl-0 [&>label]:text-klerosUIComponentsSuccess [&>label]:text-base [&>label]:font-medium" +
"before:content-[''] before:w-2 before:h-2 before:rounded-[50%] before:bg-klerosUIComponentsSuccess before:my-0 before:mr-[13px] before:ml-[3px]" +
"landscape-900:display-none"
}
>
<ChainDisplay />
</ChainConnectionContainer>
</Container>
</div>
<div
className={
"flex w-fit min-h-8 items-center pl-0 [&>label]:text-klerosUIComponentsSuccess [&>label]:text-base [&>label]:font-medium " +
"before:content-[''] before:w-2 before:h-2 before:rounded-[50%] before:bg-klerosUIComponentsSuccess before:my-0 before:mr-[13px] before:ml-[3px] " +
"landscape-900:hidden"
}
>
<ChainDisplay />
</div>
🤖 Prompt for AI Agents
In web/src/components/ConnectWallet/AccountDisplay.tsx around lines 76 to 84,
the className string is concatenated without spaces causing merged classes and
uses an invalid Tailwind class "display-none"; fix by inserting proper spaces
between each concatenated string segment (or combine into a single
string/template literal) so classes don't run together, and replace
"display-none" with the correct Tailwind utility "hidden"; ensure the resulting
className has spaces between tokens and the before: and landscape utilities
remain intact.

Comment on lines +13 to +17
className={`grid grid-cols-[16px_auto] gap-${responsiveSize(
6,
8,
300
)} items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Dynamic gap value incompatible with Tailwind.

The gap-${responsiveSize(6, 8, 300)} syntax attempts to create a Tailwind utility with a runtime JavaScript value. Tailwind's JIT compiler processes classes at build time and cannot generate utilities from dynamic values, so this gap will not apply.

Use inline styles for dynamic values:

     <div
-      className={`grid grid-cols-[16px_auto] gap-${responsiveSize(
-        6,
-        8,
-        300
-      )} items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
+      className={`grid grid-cols-[16px_auto] items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
+      style={{ gap: responsiveSize(6, 8, 300) }}
     >

Or use static responsive classes:

-      className={`grid grid-cols-[16px_auto] gap-${responsiveSize(
-        6,
-        8,
-        300
-      )} items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
+      className={`grid grid-cols-[16px_auto] gap-1.5 sm:gap-2 items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
📝 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.

Suggested change
className={`grid grid-cols-[16px_auto] gap-${responsiveSize(
6,
8,
300
)} items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
className={`grid grid-cols-[16px_auto] items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
style={{ gap: responsiveSize(6, 8, 300) }}
Suggested change
className={`grid grid-cols-[16px_auto] gap-${responsiveSize(
6,
8,
300
)} items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}
className={`grid grid-cols-[16px_auto] gap-1.5 sm:gap-2 items-center justify-start text-start text-klerosUIComponentsSecondaryText ${className}`}

Comment on lines +14 to +27
<Button
variant="primary"
small
className={
"transition duration-100 bg-transparent p-2 rounded-[7px] landscape-900:[&_button-svg]:mr-0" +
"[&_button-text]:text-KlerosUIComponentsPrimaryText [&_button-text]:font-normal" +
`[&_button-svg]:${isMobileNavbar ? "fill-KlerosUIComponentsSecondaryText" : "fill-white-75"}` +
`hover:[&_button-svg]:${
isMobileNavbar ? "fill-KlerosUIComponentsPrimaryText" : "fill-white"
} hover:bg-white-low-opacity-strong` +
`${className}`
}
{...{ text, Icon, onClick, disabled }}
/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix className concatenation spacing and color token casing.

Two critical issues:

  1. Missing spaces in concatenation: String segments joined with + lack spaces, causing classes to merge (e.g., mr-0" + "[&_button-text] becomes mr-0[&_button-text]).

  2. Inconsistent casing: Lines 19-20 use KlerosUIComponentsPrimaryText (capital K) while other files use klerosUIComponentsPrimaryText (lowercase k). Ensure consistency with your theme token naming convention.

Apply this diff:

   <Button
     variant="primary"
     small
     className={
-      "transition duration-100 bg-transparent p-2 rounded-[7px] landscape-900:[&_button-svg]:mr-0" +
-      "[&_button-text]:text-KlerosUIComponentsPrimaryText [&_button-text]:font-normal" +
-      `[&_button-svg]:${isMobileNavbar ? "fill-KlerosUIComponentsSecondaryText" : "fill-white-75"}` +
+      "transition duration-100 bg-transparent p-2 rounded-[7px] landscape-900:[&_button-svg]:mr-0 " +
+      "[&_button-text]:text-klerosUIComponentsPrimaryText [&_button-text]:font-normal " +
+      `[&_button-svg]:${isMobileNavbar ? "fill-klerosUIComponentsSecondaryText" : "fill-white-75"} ` +
       `hover:[&_button-svg]:${
-        isMobileNavbar ? "fill-KlerosUIComponentsPrimaryText" : "fill-white"
-      } hover:bg-white-low-opacity-strong` +
+        isMobileNavbar ? "fill-klerosUIComponentsPrimaryText" : "fill-white"
+      } hover:bg-white-low-opacity-strong ` +
       `${className}`
     }
     {...{ text, Icon, onClick, disabled }}
   />
📝 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.

Suggested change
<Button
variant="primary"
small
className={
"transition duration-100 bg-transparent p-2 rounded-[7px] landscape-900:[&_button-svg]:mr-0" +
"[&_button-text]:text-KlerosUIComponentsPrimaryText [&_button-text]:font-normal" +
`[&_button-svg]:${isMobileNavbar ? "fill-KlerosUIComponentsSecondaryText" : "fill-white-75"}` +
`hover:[&_button-svg]:${
isMobileNavbar ? "fill-KlerosUIComponentsPrimaryText" : "fill-white"
} hover:bg-white-low-opacity-strong` +
`${className}`
}
{...{ text, Icon, onClick, disabled }}
/>
<Button
variant="primary"
small
className={
"transition duration-100 bg-transparent p-2 rounded-[7px] landscape-900:[&_button-svg]:mr-0 " +
"[&_button-text]:text-klerosUIComponentsPrimaryText [&_button-text]:font-normal " +
`[&_button-svg]:${isMobileNavbar ? "fill-klerosUIComponentsSecondaryText" : "fill-white-75"} ` +
`hover:[&_button-svg]:${
isMobileNavbar ? "fill-klerosUIComponentsPrimaryText" : "fill-white"
} hover:bg-white-low-opacity-strong ` +
`${className}`
}
{...{ text, Icon, onClick, disabled }}
/>
🤖 Prompt for AI Agents
In web/src/components/LightButton.tsx around lines 14 to 27, the className
string concatenation is missing spaces between joined segments which causes
classes to merge, and the color token casing is inconsistent; fix by inserting
explicit spaces at the start or end of each concatenated string segment (or use
a single template literal) so classes are separated, and normalize the token
names to use the lowercase klerosUIComponentsPrimaryText and
klerosUIComponentsSecondaryText variants used elsewhere; also ensure the final
${className} is prefixed with a space so passed-in classes don’t run into the
preceding classes.

Comment on lines +5 to +8
return ReactDOM.createPortal(
<div className="fixed top-0 left-0 z-9999 w-full h-full">{children}</div>,
document.body
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use arbitrary value syntax for non-standard z-index.

The class z-9999 is not a standard Tailwind utility. In Tailwind v4, use square brackets for arbitrary values.

Apply this diff:

-    <div className="fixed top-0 left-0 z-9999 w-full h-full">{children}</div>,
+    <div className="fixed top-0 left-0 z-[9999] w-full h-full">{children}</div>,
📝 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.

Suggested change
return ReactDOM.createPortal(
<div className="fixed top-0 left-0 z-9999 w-full h-full">{children}</div>,
document.body
);
return ReactDOM.createPortal(
<div className="fixed top-0 left-0 z-[9999] w-full h-full">{children}</div>,
document.body
);
🤖 Prompt for AI Agents
In web/src/components/OverlayPortal.tsx around lines 5 to 8, the component uses
a non-standard Tailwind class `z-9999`; replace it with the Tailwind arbitrary
value syntax `z-[9999]` in the div's className so it becomes `fixed top-0 left-0
z-[9999] w-full h-full` (preserve other classes and children).

Comment on lines +75 to +78
<div
className={`w-full relative flex flex-col py-0 px-${responsiveSize(12, 32, 300)} pb-4 gap-4`}
onSubmit={handleSubmit}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Form submission broken - onSubmit handler on div element.

The component was changed from a <form> element to a <div>, but the onSubmit handler remains. The onSubmit event only fires on <form> elements, so form submission is completely broken. Users cannot save their contact details.

Additionally, the handleSubmit function signature on line 39 expects React.FormEvent<HTMLFormElement>, which is incompatible with a div.

Restore the form element:

-    <div
-      className={`w-full relative flex flex-col py-0 px-${responsiveSize(12, 32, 300)} pb-4 gap-4`}
-      onSubmit={handleSubmit}
-    >
+    <form
+      className="w-full relative flex flex-col py-0 pb-4 gap-4"
+      style={{ paddingInline: responsiveSize(12, 32, 300) }}
+      onSubmit={handleSubmit}
+    >

And close with </form> on line 118:

-    </div>
+    </form>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx
around lines 75 to 78, the element was changed from a form to a div but the
onSubmit handler (and the handleSubmit signature expecting
React.FormEvent<HTMLFormElement>) remained, breaking submission; revert the
outer element back to a <form> so onSubmit fires, ensure the element is closed
with </form> at line 118, and keep the handleSubmit signature as
React.FormEvent<HTMLFormElement> (or update it to accept the correct event if
you instead choose a different element) so types and behavior match.

Comment on lines 110 to +116
<Button
text="Save"
disabled={
!isEditingEmail || !emailIsValid || isAddingUser || isFetchingUser || isUpdatingUser || !isEmailUpdateable
}
/>
</ButtonContainer>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Issue: Button submit functionality relies on parent form.

The Button component's submit functionality will not work because the parent element is a <div> instead of a <form>. Ensure the parent element is corrected to a <form> element (flagged separately), and verify that the Button component is properly typed as type="submit".

Verify the Button component from @kleros/ui-components-library renders as a submit button:


🏁 Script executed:

#!/bin/bash
# Check if Button component usage needs explicit type="submit"
ast-grep --pattern 'Button text="Save"'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# View the actual file content around the target lines
cat "web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx" | head -120 | tail -20

Length of output: 593


🏁 Script executed:

#!/bin/bash
# Search for the Button import to understand its type signature
rg -n "import.*Button" "web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx" -A2 -B2

Length of output: 147


🏁 Script executed:

#!/bin/bash
# Look for the entire form/div structure in the file
rg -n "form|Form|<div" "web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx" -C3

Length of output: 1916


🏁 Script executed:

#!/bin/bash
# Check Button component definition in the ui-components-library
fd -t f "Button" "node_modules/@kleros/ui-components-library" 2>/dev/null | head -5

Length of output: 0


🌐 Web query:

@kleros/ui-components-library Button component type submit prop

💡 Result:

Do you want to know whether the Button supports a submit prop (and how to use it), or are you seeing an error/unexpected behavior with type="submit"?


🌐 Web query:

kleros ui-components-library Button API documentation

💡 Result:

Here’s a concise Button API summary for @kleros/ui-components-library (usage + common props). Sources: npm package page, package metadata/docs and CDN listing. [1][2][3]

Usage

  • Install: npm install @kleros/ui-components-library. Import: import { Button } from "@kleros/ui-components-library". [2][3]

Example

  • Action. [2]

Common props (supported variants may vary by package version)

  • children: ReactNode — button label/content. [2]
  • variant: string — e.g., "primary", "secondary", "danger", "ghost", "outline" (theme-specific names). [2][3]
  • size: string — e.g., "xs", "sm", "md", "lg", "xl". [2][3]
  • loading / isLoading: boolean — show loading state. [2]
  • disabled / isDisabled: boolean — disable the button. [2]
  • icon / startContent / endContent: ReactNode or icon name — render icon inside button. [2][3]
  • fullWidth / fullWidth: boolean — expand to container width. [2]
  • onClick: (e) => void — click handler. [2]

Notes

  • The library is React + TypeScript + Tailwind-based and provides a Storybook/demo; exact prop names can differ between versions—check the package README or Storybook for the release you’re using. [1][2][3]

Links / docs to inspect

  • @kleros/ui-components-library npm / README (examples & usage). [2]
  • Package metadata / security listing with component overview & install instructions. [3]
  • jsDelivr package page for version info/assets. [1]

If you want, I can open the package README/Storybook and copy the exact prop typings for the Button from the version you use — tell me which version (or grant permission to fetch latest).


🏁 Script executed:

#!/bin/bash
# Check if Button component is used elsewhere with form submission patterns
rg -n "Button.*text=" --type tsx --type ts -C2 | grep -A2 -B2 "form\|submit\|handleSubmit" | head -30

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check if there are other forms in the codebase that use Button for submission
rg -n "<form" --type tsx -A5 | grep -A5 "Button"

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for form elements with Button components using glob pattern
rg -n "<form" -g "*.tsx" -g "*.ts" -A10 | head -50

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the exact structure around the button in the target file
cat "web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx"

Length of output: 4006


Change parent <div> to <form> and add onClick handler to Button.

The parent element at line 75 is a <div> with an onSubmit handler, but onSubmit only works on <form> elements. The Button component from @kleros/ui-components-library doesn't support a type="submit" prop; it requires an onClick handler instead.

Fix required:

  1. Change line 75 from <div ... onSubmit={handleSubmit}> to <form ... onSubmit={handleSubmit}>
  2. Add onClick={handleSubmit} to the Button component (lines 110-116), or replace it with a native <button type="submit"> element
🤖 Prompt for AI Agents
In
web/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsx
around lines 75 and 110-116, the wrapper is a <div> with an onSubmit handler
(line ~75) which does nothing because onSubmit only fires on form elements; also
the Button component does not support type="submit". Change the parent from <div
... onSubmit={handleSubmit}> to <form ... onSubmit={handleSubmit}> (preserve
classes/props) and add onClick={handleSubmit} to the Button at lines 110-116 (or
replace the Button with a native <button type="submit"> if you prefer) so the
submit handler is invoked both on form submit and when the custom Button is
clicked.

const HeaderNotifs: React.FC = () => {
return <HeaderContainer>Contact Details</HeaderContainer>;
return (
<div className="flex justify-center text-base font-semibold mt-4 mb-3 text-klerosUIComponentsPrimaryText">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify custom color class generation.

The text-klerosUIComponentsPrimaryText class appears to be based on a CSS variable from @kleros/ui-components-library. Ensure that the @source directive in global.css includes the path to the library so Tailwind can scan and generate utility classes from those variables.

Based on learnings


🏁 Script executed:

#!/bin/bash
# Description: Verify that global.css includes the source directive for @kleros/ui-components-library

# Check if @source directive exists in global.css
rg -n "@source.*ui-components-library" web/src/styles/global.css

# Also check for the CSS variable definition
rg -n "klerosUIComponentsPrimaryText|--primary-text" web/

Length of output: 1506



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check how the custom Tailwind class is defined and if @source directive exists

# Check if @source directive exists in global.css
echo "=== Checking for @source directive in global.css ==="
rg -n "@source" web/src/global.css

# Check the complete global.css file head to understand its structure
echo "=== First 50 lines of global.css ==="
head -50 web/src/global.css

# Find tailwind config file
echo "=== Looking for tailwind configuration ==="
fd "tailwind\.config\.(ts|js)" web/

# Check if text-klerosUIComponentsPrimaryText is defined in global.css or tailwind config
echo "=== Searching for class definition ==="
rg -n "text-klerosUIComponentsPrimaryText|klerosUIComponentsPrimaryText.*:.*color" web/src/

Length of output: 2385



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check full global.css and find tailwind config

# Search entire global.css for the custom class definition
echo "=== Searching full global.css for text-klerosUIComponentsPrimaryText definition ==="
rg -n "text-klerosUIComponentsPrimaryText" web/src/global.css

# Search for tailwind config at repo root or in web folder
echo "=== Looking for tailwind config at repository root ==="
fd "tailwind\.config\.(ts|js|json)" .

# Check if there's a CSS class definition for this in global.css
echo "=== Checking for @apply or class definitions in global.css ==="
rg -n "^\.text-klerosUIComponentsPrimaryText|@apply.*klerosUIComponentsPrimaryText" web/src/global.css

# Check package.json for tailwind configuration
echo "=== Checking web/package.json for tailwind config ==="
jq '.tailwindConfig' web/package.json 2>/dev/null || echo "No tailwindConfig in web/package.json"

# Check if tailwind config might be in root package.json
echo "=== Checking root package.json for tailwind config ==="
jq '.tailwindConfig' package.json 2>/dev/null || echo "No tailwindConfig in root package.json"

# List all CSS files to ensure we're not missing any
echo "=== All CSS files in web/src ==="
fd "\.css$" web/src/

Length of output: 372



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check for PostCSS config and verify if custom Tailwind class is working

# Look for postcss config
echo "=== Looking for postcss configuration ==="
fd "postcss\.config\.(ts|js)" .

# Check if there's any other Tailwind setup in vite or build config
echo "=== Checking for vite.config or build configs ==="
fd "vite\.config\.(ts|js)" web/
fd "package\.json" web/ -x head -1 {}

# Check web/package.json for build scripts and dependencies
echo "=== Checking web/package.json tailwind dependency ==="
jq '.devDependencies | keys[] | select(contains("tailwind"))' web/package.json

# See if @source directive example exists anywhere in codebase
echo "=== Searching for @source examples in codebase ==="
rg -n "@source" .

# Check if there's any config in tailwind itself via theme extension
echo "=== Full global.css @theme block ==="
rg -A 200 "^@theme" web/src/global.css | head -100

Length of output: 2404



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check package.json and vite config to understand complete setup

# Get full package.json to see all dependencies
echo "=== web/package.json dependencies section ==="
jq '.dependencies, .devDependencies' web/package.json | head -40

# Check vite.config.js for Tailwind setup
echo "=== web/vite.config.js content ==="
cat web/vite.config.js

# Check if the custom class works by searching for any generate or plugin mentions
echo "=== Check if custom class is in any generated or built files ==="
fd "text-klerosUIComponentsPrimaryText" web/ --type f

Length of output: 2192


Add @source directive to generate custom Tailwind classes from @kleros/ui-components-library.

The custom Tailwind class text-klerosUIComponentsPrimaryText is used throughout the codebase but not being generated because Tailwind v4 requires an @source directive to scan external libraries for CSS variables and generate utilities from them. Without this, the class will be undefined at runtime.

Add the following to web/src/global.css after the @import statements (before or after the @theme block):

@source "../node_modules/@kleros/ui-components-library";

This tells Tailwind to scan the external library and generate utility classes from its CSS variables, enabling text-klerosUIComponentsPrimaryText and similar classes to work properly.

🤖 Prompt for AI Agents
In web/src/layout/Header/navbar/Menu/Settings/Notifications/index.tsx around
lines 10-10 the custom Tailwind class text-klerosUIComponentsPrimaryText is not
being generated; fix this by editing web/src/global.css and adding an @source
directive that points to the @kleros/ui-components-library package (place the
directive after the existing @import statements, before or after the @theme
block) so Tailwind v4 will scan the external library and generate utilities for
the custom CSS variables.

Comment on lines +19 to +25
className={
"flex flex-col items-center cursor-pointer pt-4 pb-7 px-2 max-w-[100px] rounded-[3px] gap-2 bg-klerosUIComponentsLightBackground" +
`w-[${responsiveSize(
100,
130
)}] hover:transition-[transform_0.15s,background-color_0.3s] hover:scale-[1.02] hover:bg-klerosUIComponentsLightGrey`
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Invalid className construction prevents proper styling.

Multiple issues with the className construction:

  1. String concatenation is malformed: Mixing + concatenation with template literals creates an invalid string.
  2. responsiveSize() incompatible with Tailwind: The w-[${responsiveSize(100, 130)}] syntax attempts to create a dynamic arbitrary value, but Tailwind processes classes at build time and cannot generate utilities from runtime JavaScript values.
  3. Hover classes won't apply: The hover transition classes are in a separate template literal that's concatenated, which won't be parsed correctly.

Replace with static Tailwind classes or inline styles:

-    <a
-      href={url}
-      target="_blank"
-      className={
-        "flex flex-col items-center cursor-pointer pt-4 pb-7 px-2 max-w-[100px] rounded-[3px] gap-2 bg-klerosUIComponentsLightBackground" +
-        `w-[${responsiveSize(
-          100,
-          130
-        )}] hover:transition-[transform_0.15s,background-color_0.3s] hover:scale-[1.02] hover:bg-klerosUIComponentsLightGrey`
-      }
-    >
+    <a
+      href={url}
+      target="_blank"
+      className="flex flex-col items-center cursor-pointer pt-4 pb-7 px-2 w-[100px] max-w-[130px] rounded-[3px] gap-2 bg-klerosUIComponentsLightBackground hover:transition-[transform_0.15s,background-color_0.3s] hover:scale-[1.02] hover:bg-klerosUIComponentsLightGrey"
+    >

Or use inline styles for the dynamic width:

+    <a
+      href={url}
+      target="_blank"
+      style={{ width: responsiveSize(100, 130) }}
+      className="flex flex-col items-center cursor-pointer pt-4 pb-7 px-2 max-w-[130px] rounded-[3px] gap-2 bg-klerosUIComponentsLightBackground hover:transition-[transform_0.15s,background-color_0.3s] hover:scale-[1.02] hover:bg-klerosUIComponentsLightGrey"
+    >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In web/src/layout/Header/navbar/Product.tsx around lines 19-25, the className
string is malformed and uses a runtime value inside a Tailwind arbitrary class
(w-[${responsiveSize(...)}]) which Tailwind cannot generate; fix by building a
single properly formatted className string (no broken concatenation) and move
the dynamic width into a style prop instead of a Tailwind class. Concretely:
combine all static classes into one string including hover utilities, remove the
runtime w-[...] from className, and add a style={{ width:
responsiveSize(100,130) }} (or compute a CSS value and set style={{ width:
`${value}px` }}) so the dynamic width is applied at runtime while Tailwind
classes remain static.

{!isImgLoaded ? <Skeleton width={48} height={46} circle /> : null}
<StyledImg alt={Icon} src={Icon} isLoaded={isImgLoaded} onLoad={() => setIsImgLoaded(true)} />
<img
className={`w-12 h-12 ${isImgLoaded ? "block" : "none"}`}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Invalid display utility value.

The className uses "none" as a display value, which is not a valid Tailwind utility. Use "hidden" instead to set display: none.

-          <img
-            className={`w-12 h-12 ${isImgLoaded ? "block" : "none"}`}
+          <img
+            className={`w-12 h-12 ${isImgLoaded ? "block" : "hidden"}`}
📝 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.

Suggested change
className={`w-12 h-12 ${isImgLoaded ? "block" : "none"}`}
className={`w-12 h-12 ${isImgLoaded ? "block" : "hidden"}`}
🤖 Prompt for AI Agents
In web/src/layout/Header/navbar/Product.tsx around line 31, the className
currently interpolates isImgLoaded to use the invalid Tailwind utility "none";
change that to "hidden" so the conditional becomes `isImgLoaded ? "block" :
"hidden"` to correctly toggle display with Tailwind. Ensure you update only that
string and keep the rest of the className intact so Tailwind generates the
correct classes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Frontend migration to the major update of @kleros/ui-components-library v3 with Tailwind

2 participants