className={undefined} leaves an empty class="" attribute after client rendering, so [class] selectors match
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 84/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- next.js, react, typescript
- Área
- frontend
Línea de trabajo
Empieza en packages/redact/src/dom/dom.ts, en la asignación de className que se muestra en el issue; después, ejecuta la reproducción de Next.js proporcionada e inspecciona los atributos class en la consola del navegador. El trabajo está terminado cuando un className null o undefined no deja ningún atributo class, mientras que un className con una cadena vacía sigue generando class="", como hace React.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Version: @tanstack/redact 0.2.6 through withRedact, Next.js 16.4.4 (App Router, Turbopack), react/react-dom 19.3.1, Chrome 156, production build. dom.ts is unchanged on main (049de24f).
What happens
When an HTML element is created or updated in the browser with className={undefined}, Redact leaves an empty class="" attribute. React leaves no attribute at all.
The cause is in packages/redact/src/dom/dom.ts:
(el as HTMLElement).className = next == null ? '' : '' + next;
Assigning an empty string to className creates the attribute.
| Element | React 19.3.1 | Redact 0.2.6 |
|---|---|---|
className={undefined}, server-rendered and hydrated |
no attribute | no attribute |
className={undefined}, server-rendered, then re-rendered |
no attribute | no attribute |
className={undefined}, rendered only in the browser |
no attribute | class="" |
className changes from 'x' to undefined |
no attribute | class="" |
className="" |
class="" |
class="" |
Why it matters
Selectors that test whether the attribute exists, such as section[class] or :not([class]), now match differently. CSS Modules make this easy to hit, because styles.name is undefined when a class has no rules.
We found it by comparing screenshots of our app against React baselines. An A/A run of React against itself was clean. A global section[class] rule started to apply to one section, which gained 70 px of block padding and a background, and the page grew 140 px taller. Removing the empty attribute in the browser restored the React layout exactly.
Together with #85 and #81, this keeps us from using Redact in production on Next.js.
Reproduction
package.json dependencies: [email protected], [email protected], [email protected], @tanstack/[email protected].
next.config.mjs:
import { withRedact } from '@tanstack/redact/next'
export default withRedact({})
app/layout.js:
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
app/page.js:
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
return (
<main>
<section id="ssr-undefined" className={undefined}>a</section>
<section id="ssr-empty" className="">b</section>
<section id="rerender-undefined" className={undefined} data-n={mounted ? 1 : 0}>c</section>
<section id="toggle-to-undefined" className={mounted ? undefined : 'x'}>d</section>
{mounted ? <section id="client-undefined" className={undefined}>e</section> : null}
{mounted ? <section id="client-empty" className="">f</section> : null}
</main>
)
}
Run next build && next start, open /, and run this in the console:
Object.fromEntries([...document.querySelectorAll('section')].map((e) => [e.id, e.getAttribute('class')]))
Redact 0.2.6:
{"ssr-undefined":null,"ssr-empty":"","rerender-undefined":null,"toggle-to-undefined":"","client-undefined":"","client-empty":""}
React 19.3.1:
{"ssr-undefined":null,"ssr-empty":"","rerender-undefined":null,"toggle-to-undefined":null,"client-undefined":null,"client-empty":""}
Expected
The same result as React: a null or undefined className leaves no class attribute.
Suggested fix
if (next == null) el.removeAttribute('class');
else (el as HTMLElement).className = '' + next;
- Lenguaje dominante
- TypeScript
- Estrellas
- 537
- Forks
- 22
- Merge medio
- 11 h 28 min
- PR fusionados (30 d)
- 34
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de TanStack/redact
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 55/100
TanStack/redact#144 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 48/100
TanStack/redact#141 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 68/100
TanStack/redact#139 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de TanStack/redact
Issues similares
-
area: frontend priority: normal
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
formbricks/formbricks#9918 ·
Los mantenedores suelen responder en 1 día
-
Chat: Resize question overlayAbiertoenhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
thecodacus/pithagoras#364 ·
Los mantenedores suelen responder en 1 día
-
TestAutonomousStop_ReportsObservedState fails under host load: 1s wall-clock ceiling vs 250ms cycleAbiertotype:bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
nightgauge/nightgauge#2909 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día