className={undefined} leaves an empty class="" attribute after client rendering, so [class] selectors match
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 84/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- next.js, react, typescript
- Domaine
- frontend
Piste de recherche
Commencez dans packages/redact/src/dom/dom.ts, à l’affectation de className indiquée dans l’issue, puis exécutez la reproduction Next.js fournie et examinez les attributs class dans la console du navigateur. Le travail est terminé lorsque className à null ou undefined ne laisse aucun attribut class, tandis qu’un className constitué d’une chaîne vide produit toujours class="", comme dans React.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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;
- Langage dominant
- TypeScript
- Étoiles
- 537
- Forks
- 22
- Merge moyen
- 11 h 28 min
- PR mergées (30 j)
- 34
Préparer son environnement
Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de TanStack/redact
-
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 4/5 3-5 jours Accessibilité débutants 55/100
TanStack/redact#144 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 3/5 1-2 jours Accessibilité débutants 48/100
TanStack/redact#141 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 3/5 1-2 jours Accessibilité débutants 68/100
TanStack/redact#139 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de TanStack/redact
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
caprover/caprover-frontend#273 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
ai-driven-dev/framework#1147 ·
Les mainteneurs répondent en général sous 1 jour
-
agent-ui bug p2
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
amd/gaia#6580 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
bug
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
cybersemics/em#6232 ·
Les mainteneurs répondent en général sous 1 jour