Skip to content

Commit f5bb288

Browse files
az108claude
andcommitted
Bugfix: Keep the button reset from overriding Tailwind utilities
The active and hover highlight disappeared from the sidebar items after the switch to native buttons. .btn-bare was declared outside any cascade layer while Tailwind emits its utilities inside @layer utilities. An unlayered rule outranks every layered one whatever its specificity, so the reset won against the utilities sitting on the same element and its background, padding, colour, font and text-align were applied instead of theirs. Moving the rule into the components layer, which the generated stylesheet orders before utilities, restores the intended precedence. The sidebar was the visible symptom, but the same reset was quietly beating utilities on all twelve elements using it: padding on the upload button and the slot cards, background and border on the interview process card, colour and weight on the login and registration links, alignment in the document dialog. Confirmed from the compiled stylesheet rather than by eye: .btn-bare now resolves inside the components layer while .bg-primary-hover-outlined stays in utilities. Added a guard on the declaration, since nothing else can catch this. The class is applied either way, so a component test still passes while the styling is gone, and the failure is only visible on screen. The guard was checked to fail with the rule moved back out of the layer. Verified: 2028 client tests, typecheck, eslint with no errors, a11y lint, the production build and prettier. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent cb2341f commit f5bb288

2 files changed

Lines changed: 38 additions & 11 deletions

File tree

src/main/webapp/content/scss/global.scss

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,24 @@
1111

1212
/* Visual reset for native <button> elements used purely as clickable containers
1313
(cards, list rows, icon triggers). Strips default chrome so they inherit
14-
surrounding typography and layout, while keeping their accessibility benefits. */
15-
.btn-bare {
16-
appearance: none;
17-
background: transparent;
18-
border: 0;
19-
padding: 0;
20-
margin: 0;
21-
font: inherit;
22-
color: inherit;
23-
text-align: inherit;
24-
cursor: pointer;
14+
surrounding typography and layout, while keeping their accessibility benefits.
15+
16+
Declared in the components layer on purpose. Unlayered rules outrank every layered
17+
one no matter their specificity, so leaving this outside a layer would let the reset
18+
beat the Tailwind utilities on the same element and silently drop their background,
19+
padding and colour. The components layer sits before utilities, so utilities win. */
20+
@layer components {
21+
.btn-bare {
22+
appearance: none;
23+
background: transparent;
24+
border: 0;
25+
padding: 0;
26+
margin: 0;
27+
font: inherit;
28+
color: inherit;
29+
text-align: inherit;
30+
cursor: pointer;
31+
}
2532
}
2633

2734
/* -------------------------------
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { readFileSync } from 'node:fs';
2+
import { describe, it, expect } from 'vitest';
3+
4+
/**
5+
* `.btn-bare` resets native button chrome on elements that also carry Tailwind utilities for
6+
* background, padding, colour and alignment. Unlayered rules outrank every layered one regardless
7+
* of specificity, so declaring it outside a layer makes the reset beat those utilities and silently
8+
* strips the styling from every element using it. Keeping it in the components layer, which sits
9+
* before utilities, is what lets the utilities win.
10+
*/
11+
describe('btn-bare global style', () => {
12+
const globalScss = readFileSync('src/main/webapp/content/scss/global.scss', 'utf8');
13+
14+
it('should declare btn-bare inside the components layer so utilities can override it', () => {
15+
const componentsLayer = /@layer\s+components\s*\{([\s\S]*?)\n\}/.exec(globalScss);
16+
17+
expect(componentsLayer).not.toBeNull();
18+
expect(componentsLayer?.[1]).toContain('.btn-bare');
19+
});
20+
});

0 commit comments

Comments
 (0)