Open
Conversation
A ground-up rebuild of styled-components.com on top of the prior site. Infrastructure - Migrate from Yarn 4 to pnpm 10 - Husky pre-commit hooks via lint-staged - Stop tracking tsconfig.tsbuildinfo - Sitemap, robots.txt, 404 page, error boundary - llms.txt at the project root for crawlers and AI agents - Asset proxy route for badge images Design system - OKLCH color tokens for consistent perceptual lightness across light/dark - Theme toggle with light / dark / auto and CSS-first FOUC prevention - Typography system with display/sans/mono families - Global styles - Custom logo concepts component Navigation - Sidebar-first navigation with scroll-spy section highlighting - Sidebar fold/unfold for narrower viewports - Breadcrumbs and per-page navigation - Mobile navbar with collapsing sections Homepage - Redesigned hero with celebration effect and live editor - Showcase strip and "as seen at" company logos - Latest blog post card on the index Blog - Full blog section with Medium content migration - Post listing with year grouping, individual post pages, sidebar - 16 archived posts plus the decade retrospective Cleanup - Remove dead components (BlmBanner, Loading, NavLinks, SeoHead, WithIsScrolled) - Drop snapshot-only test files - Drop dead utils (escape, fonts, pathnameToTitle, stripIndent)
Comprehensive update of the documentation corpus to cover styled-components v6.4. Adds new API references, expands existing guides, and tightens version labels and language to match actual shipping behavior. New API references - createTheme: full reference for the v6.4 CSS-variable theming utility, including dark mode patterns and Shadow DOM usage - stylisPluginRSC: documented in StyleSheetManager and the SSR section - CSP nonce sources documented in Security with all five supply methods - attrs improvements: optional-prop typing covered in the basics section RSC and SSR coverage - React Server Components section in the SSR guide with do/don't tables - Child-index selector caveat with the universal :first-of-type fix - StyleSheetManager-in-RSC behavior documented at the API level - Theming with CSS custom properties for RSC environments Migration guide - New "Notable changes in v6.4" section covering createTheme, stylisPluginRSC, StyleSheetManager-in-RSC, CSP nonce, attrs changes, faster re-renders, the Metro/Expo nanoid fix, and the IE11 build target removal (with provenance to #3333 and #4292) - Browser support FAQ reframed: v6 has not officially supported IE11 since the August 2021 v6 planning issue; v6.4 just aligns the compile target Dark mode - Step-by-step dark mode guide using createTheme + the css partial + GlobalStyle overrides + the localStorage anti-flash script Performance - One-line callout that v6.4 re-renders skip style work entirely when props and theme are unchanged - Reframed implementation-detail wording (e.g. "hash recomputed every render") to observable cause-and-effect llms.txt - Full rewrite covering RSC, createTheme, stylisPluginRSC, attrs changes, CSP nonce, faster re-renders, RN fixes, and IE11 framing Cleanup of pre-existing inaccuracies - Removed implementation-detail leaks from API reference docs - Fixed invalid quoted CSS values in the homepage getting-started example - Tightened "v6.3.0+" labels to be precise about what shipped where
Replace Prettier 2.8.8 with the oxc toolchain. oxfmt 0.44.0 is 100%
Prettier v3.8 conformant for JS/TS and ~30x faster. oxlint 1.59.0 adds
linting (none was previously configured).
Tooling
- prettier devDep removed; oxfmt + oxlint added (pinned)
- .prettierrc replaced with .oxfmtrc.json (migrated via oxfmt --migrate=prettier)
- .oxlintrc.json with the correctness-focused plugin set:
typescript, unicorn, oxc, react, nextjs, jsx-a11y, import, promise, jest
- categories: correctness=error, suspicious=warn
- Three rules disabled as noise:
- react/react-in-jsx-scope (obsolete since the React 17 JSX transform)
- import/no-named-as-default (would flag the canonical
`import styled from 'styled-components'` idiom)
- import/no-unassigned-import (flags CSS side-effect imports)
- Scripts: `format`, `format:check`, `lint`
- lint-staged runs jest + oxfmt + oxlint on staged JS/TS
Codebase changes surfaced and resolved by the new tooling
- Reformat across 14 files (Prettier 2 -> Prettier 3.8 idioms)
- Removed dead `description` plumbing from BlogListPage / BlogPostPage /
blog/[slug]/page.tsx -> DocsLayout (SEO descriptions live in
generateMetadata, the prop was never rendered)
- Added explicit keys to array-rendered JSX in elementToText.spec.tsx
- CaptureScroll: collapsed two useCallbacks into one effect with a
captured `node` const, fixing the ref-in-cleanup pitfall
- useScrollSpy: extracted `idsKey = ids.join(',')` outside the effect,
re-derived `localIds` inside, gave the linter a single string dep
- Migrated raw <img> in Slider/Navigation and the showcase page to
next/image with `fill` and explicit `sizes`
- NavButton in Slider/Navigation: removed dead role/tabIndex (the
parent Next.js Link is the actual interactive element)
- Renamed shadowed variables in ThemeToggle, companies-manifest,
app/docs/page.tsx
- Replaced two `Array#sort()` calls with `Array#toSorted()` for
immutability
- Added `return null` to the docsearch import().then() handler
- Removed unused imports (`css`, `font`) and unused catch binding
- Bumped markdown-to-jsx 9.7.11 -> 9.7.14: the published 9.7.11 dist
was missing the .d.ts/.d.cts entry-point declarations referenced by
the exports map, breaking TS7016 in consuming pages
…tion The plugin's rule count has changed since this line was written and will change again. Describe the qualitative shape of the plugin instead of quoting a number that goes stale and erodes trust.
Bumps dev dependencies to versions where the previously-vulnerable transitive deps (handlebars, minimatch, picomatch, micromatch, yaml, brace-expansion) are either resolved naturally or coverable by overrides. Direct devDep upgrades: - husky 8.0.3 -> 9.1.7 (drops the husky.sh shebang and the duplicate postinstall hook; uses `prepare: husky` per the v9 migration guide) - lint-staged 13.2.2 -> 16.4.0 - jest 29.5.0 -> 30.3.0 - @types/jest 29.5.1 -> 30.0.0 - jest-environment-jsdom -> 30 (was already 30.2.0; now floats to 30.x) - ts-jest 29.1.0 -> 29.4.9 These upgrades alone resolved 10 of the 18 vulnerabilities. For the remaining 8 (transitive deps that the upgraded packages still pull at vulnerable versions), pnpm.overrides forces safe versions: - brace-expansion ^1.1.13 - minimatch ^3.1.5 - picomatch@<3 ^2.3.2 (for the 2.x consumers in jest-haste-map and jest-message-util) - picomatch@>=4 <5 ^4.0.4 (for the 4.x consumers in fast-glob and jest-environment-jsdom) Picomatch needs the scoped overrides because both the 2.x and 4.x lines are simultaneously consumed by different parts of the dep tree, and a single top-level override would force one or the other and break semver expectations on the side that didn't match. `pnpm audit`: 0 vulnerabilities. tsc, oxlint, oxfmt --check, jest, and build all pass.
Bug fixes
- ThemeToggle: cycling never reached `auto` for users on system-dark.
`getTheme()` was reading the html `dark` class, but the inline
themeScript adds that class for both "explicit dark" and "auto +
system-dark", so the two cases were indistinguishable. Read
localStorage directly instead.
- CaptureScroll: module-level `wheel` listener was non-passive,
forcing the browser to wait on it for every scroll event app-wide.
Marked `{ passive: true }`.
- PlatonicLogo: the morph interval ran forever in the global navbar
even when the tab was hidden. Now pauses on `visibilitychange`.
- Asset proxy: `size.svg` was hardcoded to a stale "12.4 kB" badge URL.
Removed the entry and the corresponding badge from the homepage.
Dead code
- Deleted components/Nav/BlogSidebarMenu.tsx (115 lines, no consumers)
- Removed unused $active prop from TopLink and CategoryLink in
SidebarMenus
- Removed empty `FooterLink = styled(Link)` wrapper in Footer
Reuse
- app/not-found.tsx: dropped local titleToDash, imported the existing
utils/titleToDash
- ThemeToggle: replaced 60 lines of hand-rolled SVG icons with
LightMode / DarkMode / BrightnessAuto from @styled-icons/material
- DotSeparator: extracted shared `<DotSeparator>` component, replaces
byte-identical Sep/Separator definitions in BlogListPage and BlogMeta
- HomepageBadges: collapsed four near-identical anchor blocks into a
BADGES array + .map
- Breadcrumbs: derive DOCS_CATEGORY_LABELS from app/docs.json instead
of maintaining a parallel hand-keyed table; resolve blog post titles
via postBySlug
Net: -156 lines.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
…ient component The blog pages used a `createGlobalStyle` rendered inside the BlogPostPage client component to set max-width and image styles on the content wrapper. With JS disabled the layout was stable (the rule landed in the SSR registry), but on hydration the styled-components client runtime took over and the brief SSR-style → client-style handoff caused visible text reflow as the rule re-applied. These rules don't depend on any runtime values, so they don't need styled-components at all. Moved them to a static `app/blog/blog.css` imported via a new `app/blog/layout.tsx` route layout. The CSS is in the page from first paint via Next.js's CSS pipeline, and there's no SSR-to-client style handoff to flicker.
Blog section - Year-as-poster list layout with sticky spine, warm blogAccent color - Split BlogMeta into byline (top) and colophon (bottom) - Magazine HR treatment scoped to blog routes - Drop 100ch content cap so blog matches docs width Layout - Add theme.layout.gutterFluid (clamp(2rem, 5vw, 5rem)) token - Navbar and docs/blog/hero content share the same fluid gutter - HeroContent styled component replaces plain .hero-content class - Update markdown-to-jsx to 9.7.15 (restores releases page) Syntax highlighting - Unify all code blocks through HighlightedCode component — static CodeBlock, interactive LiveEdit, and HomepageHeroEditor share the same annotation pipeline and token rendering - Extract codeTextMixin so all code blocks share font weight, colors, family, and letter-spacing - CSS grammar extension: tokenize CSS value keywords (inline-block, ease-in-out, all, etc.) as constants - TSX grammar extension: re-tokenize __html template literals as JS so dangerouslySetInnerHTML script content gets full highlighting - TSX grammar extension: recognize styled.div<Generic> template literals so their CSS content still renders with CSS sub-grammar - JSX tag depth annotator: 4-level complementary palette (cyan, blue, amber, teal) stamped on tag fragments only, not embedded JS inside attribute expressions - Property access chain depth: stamp deep class on 2nd+ member so the leaf of props.theme.fg renders distinctly - Optional chaining fix: stamp property-access on identifiers after ?. so the depth counter continues through them - Function machinery group: attr-name, arrow, and parameter share brand pink with function calls - Operators removed from theme dict so arrow wins cascade - Code palette matches PlatonicLogo brightness profile in dark mode (L 0.82, high chroma across all chromatic tokens) - Warm-tinted neutrals (hue 60) so code text feels inky not disabled - codeProperty and codePropertyDeep for chain members - Medium font weight in light mode, light weight in dark mode
Navigation alignment
- Navbar ContentZone mirrors Layout.Content's 120ch + auto-margin box
model so desktop items align with content edges at wide viewports
- MobileNavbar pads to the content gutter minus each button's icon inset
so hamburger and theme toggle icons land on the content edge
- Extract theme.layout.contentWidth (120ch) for reuse between Content
and ContentZone
styled-components
- Bump to 6.4.0-prerelease.14 (from .9)
- GlobalStyles dark color overrides now use theme.vars.color[key]
instead of hand-rolled --sc-color-${key} strings — names track the
createTheme prefix automatically
llms.txt corrections
- ThemeProvider must receive the raw theme object, not the createTheme
output (passing the output produces self-referential var(--x, fallback)
CSS). Added empirical wiring example.
- theme.GlobalStyle renders nothing without a ThemeProvider ancestor
- Dark mode example uses theme.vars for bare property names
- Added gotchas: @Property for animatable tokens, Next.js 16 <style>
precedence + href for streaming dedup, dual class + data-theme signal
for DocSearch-style integrations
- Cut mid-prerelease narration and decorative bold emphasis
AGENTS.md
- New "Read first" section directs agents at public/llms.txt before
touching createTheme, ThemeProvider, createGlobalStyle, and related
APIs — trust the doc over training-data assumptions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.