Skip to content

CSS resets can no longer restyle the picker; content passed in keeps its own styles (0.2.0) - #4

Merged
rishimohan merged 2 commits into
mainfrom
fix/css-reset-proof
Oct 5, 2026
Merged

rishimohan merged 2 commits into
mainfrom
fix/css-reset-proof

Conversation

@rishimohan

Copy link
Copy Markdown
Owner

Why

In 21st.dev's sandbox the picker rendered flat: no panel padding, square gradient stops, no borders. Colorshot's stylesheet loaded before Tailwind's, so @layer colorshot was declared first and lost to Tailwind v4's preflight in @layer base. Tailwind v3's preflight is unlayered and stripped the stop borders in any order. Any app that imports Colorshot's CSS before its own hits the same thing.

What changed

  • Reset-proof styles. Only the --cs-* theme tokens stay in @layer colorshot, so app CSS still sets them without !important. Every other rule is unlayered and scoped to [data-colorshot], so element and universal resets cannot override it. packages/styles/scripts/layers.mjs (postcss) does the split at build time, and the playground and site run the same transform, so dev and tests see the published cascade. All 1,077 declarations are preserved.
  • Content passed in keeps its own styles. ColorPicker children and the Vue default slot render inside <div data-part="slot"> (display: contents, layout unchanged). Colorshot's element rules (button/input reset, box-sizing, focus outline, transition locks) skip it via :not(:where(...)), which adds no specificity. A plain <button> there gets Colorshot's control look; a button with any class is styled by the app alone, including Tailwind utilities.
  • Small consistency fixes. The ColorField trigger sets its own line-height. Icons are display: block, so the format menu check and menu icons sit centered on their labels, as they already did in Tailwind apps.
  • Docs. README, llms.txt, skill and site: tokens are set on the picker (not a parent, which never worked), part overrides need Colorshot's selector and must load after its CSS, and the new slot part is documented.
  • Version 0.2.0 (minor): part overrides now depend on load order and selector strength, instead of any unlayered CSS winning.

Tests

  • e2e/css-resets.spec.ts: Tailwind v4 and v3 preflight plus global form-control styles, loaded before and after Colorshot, across 9 picker states (solid, gradients, dark, small/inset, ColorField, search open, format menu open, focus ring). Element boxes and visible styles must not change. Also checks that token overrides and layout utilities (margin) still apply. Fails on 0.1.0's CSS in exactly the 5 broken setups.
  • e2e/slot.spec.ts: class-styled children keep their styles (plain CSS and @layer utilities), plain buttons get the control look, Vue slot, layout and focus.
  • Visual check against 0.1.0 across 20 cases: pixel-identical except the intended changes (slot button, centered menu icons, trigger text up to 1px).
  • 294 e2e (Chromium, Firefox, WebKit) and 189 unit tests pass. styles.css is 7,964 B gzipped, so its budget moves from 7,925 to 8,000 B.

After merge

Publish 0.2.0, then upgrade Orshot (the "Pick from library" button inside the picker gets its own styling back) and update the Orshot Colorshot page copy that says tokens work on any parent.

…n keeps its own styles

- Only the --cs-* theme tokens stay in @layer colorshot; every other rule is unlayered and scoped to
  [data-colorshot] (scripts/layers.mjs splits the layer at build time and in the playground and site).
  Tailwind v4's preflight loaded after Colorshot used to flatten the panel, and v3's removed the stop borders.
- ColorPicker children and the Vue default slot render in <div data-part="slot"> (display: contents).
  Element rules skip it; a plain <button> there gets the control look, a button with a class is the app's.
- ColorField trigger sets its own line-height; icons are display: block, so the menu checks sit centered.
- e2e: Tailwind v3/v4 preflight and global control styles in both load orders across picker states,
  slot styling in React and Vue. Docs: tokens are set on the picker, not a parent; part overrides load after.
@rishimohan
rishimohan merged commit b16e7bd into main Oct 5, 2026
2 checks passed
@rishimohan
rishimohan deleted the fix/css-reset-proof branch October 5, 2026 04:24
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.

1 participant