fix: Fix HyperDX primary button styling and SSR hydration (#1706)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Elizabet Oliveira 2026-02-06 18:29:03 +00:00 committed by GitHub
parent 6241c38892
commit 42820f3925
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 12 deletions

View file

@ -0,0 +1,7 @@
---
'@hyperdx/app': patch
---
fix: Apply theme CSS class during SSR to prevent button styling mismatch
Adds the theme class (e.g., `theme-hyperdx`) to the HTML element during server-side rendering in `_document.tsx`. This ensures CSS variables for button styling are correctly applied from the first render, preventing a hydration mismatch that caused primary buttons to display with Mantine's default styling instead of the custom theme styling when `NEXT_PUBLIC_THEME` was explicitly set.

View file

@ -2,6 +2,17 @@ import { Head, Html, Main, NextScript } from 'next/document';
import { ibmPlexMono, inter, roboto, robotoMono } from '@/fonts';
// Get theme class for SSR - must match ThemeProvider's resolution
// This ensures CSS variables are applied during server-side rendering
// to prevent hydration mismatch with button styling
function getThemeClass(): string {
const envTheme = process.env.NEXT_PUBLIC_THEME;
// Default to hyperdx if not set or invalid
const themeName =
envTheme === 'hyperdx' || envTheme === 'clickstack' ? envTheme : 'hyperdx';
return `theme-${themeName}`;
}
export default function Document() {
const fontClasses = [
ibmPlexMono.variable,
@ -10,8 +21,10 @@ export default function Document() {
roboto.variable,
].join(' ');
const themeClass = getThemeClass();
return (
<Html lang="en" className={fontClasses}>
<Html lang="en" className={`${fontClasses} ${themeClass}`}>
<Head>
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
<script src="/__ENV.js" />

View file

@ -30,10 +30,10 @@
--color-bg-danger: var(--mantine-color-red-4);
--color-bg-warning: var(--mantine-color-orange-5);
/* Primary Button */
--color-primary-button-bg: var(--palette-brand-300);
--color-primary-button-bg-hover: var(--color-brand-200);
--color-primary-button-text: var(--color-text-inverted);
/* Primary Button - uses brand green colors */
--color-primary-button-bg: var(--mantine-color-green-light);
--color-primary-button-bg-hover: var(--mantine-color-green-light-hover);
--color-primary-button-text: var(--mantine-color-green-light-color);
/* Borders & Dividers */
--color-border: var(--mantine-color-dark-5);
@ -136,6 +136,11 @@
--color-bg-danger: var(--mantine-color-red-8);
--color-bg-warning: var(--mantine-color-orange-8);
/* Primary Button - uses brand green colors */
--color-primary-button-bg: var(--mantine-color-green-light);
--color-primary-button-bg-hover: var(--mantine-color-green-light-hover);
--color-primary-button-text: var(--mantine-color-green-light-color);
/* Borders & Dividers - inverted */
--color-border: var(--mantine-color-gray-1);
--color-border-muted: rgb(0 0 0 / 5%);

View file

@ -243,11 +243,12 @@ export const makeTheme = ({
baseVars['--button-fz'] = rem(12);
}
// Use Mantine's built-in CSS vars for hover support
// Use semantic CSS vars for primary button styling
if (props.variant === 'primary') {
baseVars['--button-bg'] = 'var(--mantine-color-green-light)';
baseVars['--button-hover'] = 'var(--mantine-color-green-light-hover)';
baseVars['--button-color'] = 'var(--mantine-color-green-light-color)';
baseVars['--button-bg'] = 'var(--color-primary-button-bg)';
baseVars['--button-hover'] = 'var(--color-primary-button-bg-hover)';
baseVars['--button-color'] = 'var(--color-primary-button-text)';
baseVars['--button-color-hover'] = 'var(--color-primary-button-text)';
}
if (props.variant === 'secondary') {
@ -305,9 +306,9 @@ export const makeTheme = ({
}
if (props.variant === 'primary') {
baseVars['--ai-bg'] = 'var(--mantine-color-green-light)';
baseVars['--ai-hover'] = 'var(--mantine-color-green-light-hover)';
baseVars['--ai-color'] = 'var(--mantine-color-green-light-color)';
baseVars['--ai-bg'] = 'var(--color-primary-button-bg)';
baseVars['--ai-hover'] = 'var(--color-primary-button-bg-hover)';
baseVars['--ai-color'] = 'var(--color-primary-button-text)';
}
if (props.variant === 'secondary') {