[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"quiz-css-color-scheme-native-dark-mode-form-controls":44,"search-suggestions":60,"quiz-article-css-color-scheme-native-dark-mode-form-controls":106},[4,20,32],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,{"id":45,"slug":46,"kind":47,"title":48,"description":49,"config":50,"verticalId":5,"vertical":55,"course":52,"_count":56,"access":57,"attempts":59,"questionCount":51},"01a09a84-4208-704f-a077-ac721e62cc55","css-color-scheme-native-dark-mode-form-controls","PRACTICE_QUIZ","CSS color-scheme — native dark mode for form controls","Seven questions on what color-scheme actually fixes, what it leaves alone, and the two keywords (light dark and only) that trip people up.",{"questionCount":51,"timeLimitSec":52,"shuffleQuestions":18,"shuffleOptions":17,"negativeMarking":19,"passScorePct":53,"maxAttempts":52,"revealAnswers":54,"allowFlagging":18,"allowBacktracking":17},7,null,70,"AFTER_SUBMIT",{"slug":6,"name":7},{"questions":51},{"allowed":17,"reason":58},"FREE",[],[61,65,69,73,77,81,85,89,92,96,99,103],{"slug":62,"name":63,"articles":64},"webdev","Webdev",100,{"slug":66,"name":67,"articles":68},"javascript","Javascript",83,{"slug":70,"name":71,"articles":72},"frontend","Frontend",71,{"slug":74,"name":75,"articles":76},"css","Css",34,{"slug":78,"name":79,"articles":80},"tutorial","Tutorial",28,{"slug":82,"name":83,"articles":84},"typescript","Typescript",15,{"slug":86,"name":87,"articles":88},"react","React",12,{"slug":90,"name":91,"articles":88},"performance","Performance",{"slug":93,"name":94,"articles":95},"node","Node",9,{"slug":97,"name":98,"articles":95},"browser","Browser",{"slug":100,"name":101,"articles":102},"accessibility","Accessibility",6,{"slug":104,"name":105,"articles":102},"grammar","Grammar",{"id":107,"slug":46,"title":108,"subtitle":52,"excerpt":109,"coverUrl":110,"locale":13,"readingMinutes":111,"publishedAt":112,"viewCount":113,"likeCount":19,"commentCount":19,"author":114,"vertical":119,"topic":120,"tags":122,"_count":127,"playground":129,"body":131,"bodyMd":245,"seo":246,"translationGroupId":249,"series":52,"podcastUrl":52,"verticalId":5,"thread":250,"assessments":252,"translations":255,"quiz":257},"01a09a84-4147-713b-b0e9-9ffc501e378b","The CSS Property That Fixes Dark Mode's Ugly White Boxes","You shipped dark mode. The page is black, the text is white — and then the date picker opens like a floodlight. color-scheme is the one-line CSS property that tells the browser your native form controls need to catch up too.","\u002Fmedia\u002Fcovers\u002Fcss-color-scheme-native-dark-mode-form-controls.png",4,"2026-09-18T10:53:36.839Z",11,{"id":115,"name":116,"username":117,"avatarUrl":52,"headline":118},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":74,"name":121},"CSS",[123,124,125,126],{"slug":74,"name":75,"color":52},{"slug":62,"name":63,"color":52},{"slug":70,"name":71,"color":52},{"slug":100,"name":101,"color":52},{"assessments":128},1,{"slug":46,"title":130},"color-scheme — interactive playground",{"blocks":132,"version":128},[133,137,140,145,148,153,156,159,163,166,170,173,176,179,182,185,188,191,194,197,200,203,208,211,214,217,220,223,226,229,232,235,238],{"id":134,"html":135,"type":136},"b1","\u003Cp>Dark mode ships. Design review looks great — black background, white text, the brand&#39;s neon-green accent on every button. Then QA opens the signup form at 11pm to test the date-of-birth field, clicks the date input, and a white rectangle the size of a business card lights up the middle of an otherwise black screen like someone left a monitor on in a dark room.\u003C\u002Fp>","paragraph",{"id":138,"html":139,"type":136},"b2","\u003Cp>Same story for the \u003Ccode>&lt;select&gt;\u003C\u002Fcode> dropdown. Same for the scrollbar, which is still the pale gray default sitting on a black sidebar like a chalk mark. Nobody wrote CSS for any of this — because none of it \u003Cem>is\u003C\u002Fem> your CSS. It&#39;s the browser&#39;s own rendering of the form controls you didn&#39;t touch, and it&#39;s still light-mode, because you never told it your page has an opinion about that.\u003C\u002Fp>",{"id":141,"html":142,"text":143,"type":144,"level":31},"b3","The instinct that doesn&#39;t fix it","The instinct that doesn't fix it","heading",{"id":146,"html":147,"type":136},"b4","\u003Cp>The obvious move is to go after the controls directly:\u003C\u002Fp>",{"id":149,"code":150,"type":151,"language":74,"highlight":152},"b5","input[type=\"date\"],\nselect {\n  background: #1a1a1a;\n  color: #f0f0f0;\n  border: 1px solid #333;\n}","code",[],{"id":154,"html":155,"type":136},"b6","\u003Cp>That recolors the \u003Cem>box\u003C\u002Fem> — the input&#39;s own background and border pick up the dark theme fine. Click into the date field, though, and the calendar popup that the browser draws on top — the actual day grid, the month header, the little arrows — is still a plain white pop-up. None of that inner UI is a DOM node you can select. It&#39;s OS\u002Fbrowser chrome, painted by an internal rendering path your stylesheet has no hooks into, the same way \u003Ccode>&lt;select&gt;\u003C\u002Fcode>&#39;s dropdown list is native chrome even though the closed box isn&#39;t.\u003C\u002Fp>",{"id":157,"html":158,"type":136},"b7","\u003Cp>So people escalate: hide the native calendar, build a custom date-picker component instead, ship a dropdown-replacement library for \u003Ccode>&lt;select&gt;\u003C\u002Fcode>, and now dark mode has cost a design system&#39;s worth of rebuilt widgets — for a fix that&#39;s one declaration.\u003C\u002Fp>",{"id":160,"html":161,"text":162,"type":144,"level":31},"b8","What&#39;s actually happening","What's actually happening",{"id":164,"html":165,"type":136},"b9","\u003Cp>Browsers ship two built-in palettes for their own native UI — form controls, native popups, scrollbars — a light one and a dark one. By default every page gets the light one, regardless of your page&#39;s own background, because the browser has no idea your page supports dark rendering unless you say so. That&#39;s the missing piece: not &quot;how do I recolor a date picker,&quot; but &quot;how do I tell the browser which of its two built-in palettes to use.&quot;\u003C\u002Fp>",{"id":167,"code":168,"type":151,"language":74,"highlight":169},"b10",":root {\n  color-scheme: light dark;\n}",[],{"id":171,"html":172,"type":136},"b11","\u003Cp>One line, set once. It tells the browser: \u003Cem>this page supports both schemes — pick whichever matches the user&#39;s OS preference (\u003Ccode>prefers-color-scheme\u003C\u002Fcode>), and paint your own native UI accordingly.\u003C\u002Fem> The calendar popup, the \u003Ccode>&lt;select&gt;\u003C\u002Fcode> dropdown list, and the scrollbar track and thumb all now render in the dark palette when the user&#39;s system is set to dark, with zero JavaScript and no rebuilt widgets, because the browser was already capable of this. It just needed to be told your page opted in.\u003C\u002Fp>",{"id":174,"html":175,"type":136},"b12","\u003Cp>Poke at the difference directly — same markup, one property toggled:\u003C\u002Fp>",{"id":177,"html":178,"type":136},"b13","\u003C!-- playground:start -->",{"id":180,"html":181,"text":181,"type":144,"level":31},"b14","🎮 Try it yourself",{"id":183,"html":184,"type":136},"b15","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":186,"html":187,"type":136},"b16","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":189,"html":190,"type":136},"b17","\u003C!-- playground:end -->",{"id":192,"html":193,"text":193,"type":144,"level":31},"b18","The part that trips people up next",{"id":195,"html":196,"type":136},"b19","\u003Cp>\u003Ccode>color-scheme\u003C\u002Fcode> repaints the browser&#39;s \u003Cem>own\u003C\u002Fem> rendering — not your components. If you built a custom-styled checkbox with \u003Ccode>appearance: none\u003C\u002Fcode> and hand-drawn states, or a \u003Ccode>&lt;div&gt;\u003C\u002Fcode>-based dropdown, \u003Ccode>color-scheme\u003C\u002Fcode> has nothing to do with it; that&#39;s still entirely your CSS to theme, same as before. This property closes the gap on the controls you \u003Cem>didn&#39;t\u003C\u002Fem> rebuild — it&#39;s not a blanket dark-mode switch for the page.\u003C\u002Fp>",{"id":198,"html":199,"type":136},"b20","\u003Cp>Two refinements worth knowing once the basic version is in:\u003C\u002Fp>",{"id":201,"html":202,"type":136},"b21","\u003Cp>\u003Cstrong>The meta tag beats the flash.\u003C\u002Fstrong> CSS only applies once it&#39;s parsed and downloaded — the browser has already started laying out the page before then. Add the equivalent as a \u003Ccode>&lt;meta&gt;\u003C\u002Fcode> tag in \u003Ccode>&lt;head&gt;\u003C\u002Fcode>, and the browser knows before your stylesheet even arrives, which kills the flash of a light-mode scrollbar for one frame before the dark one swaps in:\u003C\u002Fp>",{"id":204,"code":205,"type":151,"language":206,"highlight":207},"b22","\u003Cmeta name=\"color-scheme\" content=\"light dark\" \u002F>","html",[],{"id":209,"html":210,"type":136},"b23","\u003Cp>\u003Cstrong>\u003Ccode>only\u003C\u002Fcode> forces the issue.\u003C\u002Fstrong> An app that&#39;s intentionally dark all the time — a code editor, a terminal emulator — doesn&#39;t want to follow the user&#39;s OS preference at all. \u003Ccode>color-scheme: only dark\u003C\u002Fcode> pins the native UI to dark regardless of what \u003Ccode>prefers-color-scheme\u003C\u002Fcode> reports, which is different from \u003Ccode>color-scheme: dark\u003C\u002Fcode> alone (which still nudges but can be overridden by things like a forced-colors mode). Reach for \u003Ccode>only\u003C\u002Fcode> when the design genuinely isn&#39;t offering a light variant, not as a default.\u003C\u002Fp>",{"id":212,"html":213,"type":136},"b24","\u003C!-- quiz:start -->",{"id":215,"html":216,"text":216,"type":144,"level":31},"b25","🧠 Test yourself",{"id":218,"html":219,"type":136},"b26","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls\u002Fquiz\">Take the 7-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":221,"html":222,"type":136},"b27","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":224,"html":225,"type":136},"b28","\u003C!-- quiz:end -->",{"id":227,"html":228,"type":136},"b29","\u003Cp>Next time a dark-mode bug shows up as &quot;the calendar popup is still white,&quot; check for \u003Ccode>color-scheme\u003C\u002Fcode> before reaching for a rebuilt date-picker component. What native control in your own app have you been secretly overriding by hand that this one line already covers?\u003C\u002Fp>",{"id":230,"type":231},"b30","divider",{"id":233,"html":234,"type":136},"b31","\u003Cp>🚀 \u003Cstrong>Want more like this?\u003C\u002Fstrong> Every guide, playground, and quiz lives on \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">bestpractic.org\u003C\u002Fa>\u003C\u002Fstrong> — open it and \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">sign up free\u003C\u002Fa>\u003C\u002Fstrong> so the next one finds you.\u003C\u002Fp>",{"id":236,"html":237,"type":136},"b32","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":239,"type":240,"items":241,"ordered":18},"b33","list",[242,243,244],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","Dark mode ships. Design review looks great — black background, white text, the brand's neon-green accent on every button. Then QA opens the signup form at 11pm to test the date-of-birth field, clicks the date input, and a white rectangle the size of a business card lights up the middle of an otherwise black screen like someone left a monitor on in a dark room.\n\nSame story for the `\u003Cselect>` dropdown. Same for the scrollbar, which is still the pale gray default sitting on a black sidebar like a chalk mark. Nobody wrote CSS for any of this — because none of it *is* your CSS. It's the browser's own rendering of the form controls you didn't touch, and it's still light-mode, because you never told it your page has an opinion about that.\n\n## The instinct that doesn't fix it\n\nThe obvious move is to go after the controls directly:\n\n```css\ninput[type=\"date\"],\nselect {\n  background: #1a1a1a;\n  color: #f0f0f0;\n  border: 1px solid #333;\n}\n```\n\nThat recolors the *box* — the input's own background and border pick up the dark theme fine. Click into the date field, though, and the calendar popup that the browser draws on top — the actual day grid, the month header, the little arrows — is still a plain white pop-up. None of that inner UI is a DOM node you can select. It's OS\u002Fbrowser chrome, painted by an internal rendering path your stylesheet has no hooks into, the same way `\u003Cselect>`'s dropdown list is native chrome even though the closed box isn't.\n\nSo people escalate: hide the native calendar, build a custom date-picker component instead, ship a dropdown-replacement library for `\u003Cselect>`, and now dark mode has cost a design system's worth of rebuilt widgets — for a fix that's one declaration.\n\n## What's actually happening\n\nBrowsers ship two built-in palettes for their own native UI — form controls, native popups, scrollbars — a light one and a dark one. By default every page gets the light one, regardless of your page's own background, because the browser has no idea your page supports dark rendering unless you say so. That's the missing piece: not \"how do I recolor a date picker,\" but \"how do I tell the browser which of its two built-in palettes to use.\"\n\n```css\n:root {\n  color-scheme: light dark;\n}\n```\n\nOne line, set once. It tells the browser: *this page supports both schemes — pick whichever matches the user's OS preference (`prefers-color-scheme`), and paint your own native UI accordingly.* The calendar popup, the `\u003Cselect>` dropdown list, and the scrollbar track and thumb all now render in the dark palette when the user's system is set to dark, with zero JavaScript and no rebuilt widgets, because the browser was already capable of this. It just needed to be told your page opted in.\n\nPoke at the difference directly — same markup, one property toggled:\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n## The part that trips people up next\n\n`color-scheme` repaints the browser's *own* rendering — not your components. If you built a custom-styled checkbox with `appearance: none` and hand-drawn states, or a `\u003Cdiv>`-based dropdown, `color-scheme` has nothing to do with it; that's still entirely your CSS to theme, same as before. This property closes the gap on the controls you *didn't* rebuild — it's not a blanket dark-mode switch for the page.\n\nTwo refinements worth knowing once the basic version is in:\n\n**The meta tag beats the flash.** CSS only applies once it's parsed and downloaded — the browser has already started laying out the page before then. Add the equivalent as a `\u003Cmeta>` tag in `\u003Chead>`, and the browser knows before your stylesheet even arrives, which kills the flash of a light-mode scrollbar for one frame before the dark one swaps in:\n\n```html\n\u003Cmeta name=\"color-scheme\" content=\"light dark\" \u002F>\n```\n\n**`only` forces the issue.** An app that's intentionally dark all the time — a code editor, a terminal emulator — doesn't want to follow the user's OS preference at all. `color-scheme: only dark` pins the native UI to dark regardless of what `prefers-color-scheme` reports, which is different from `color-scheme: dark` alone (which still nudges but can be overridden by things like a forced-colors mode). Reach for `only` when the design genuinely isn't offering a light variant, not as a default.\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 7-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls\u002Fquiz)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n\nNext time a dark-mode bug shows up as \"the calendar popup is still white,\" check for `color-scheme` before reaching for a rebuilt date-picker component. What native control in your own app have you been secretly overriding by hand that this one line already covers?\n\n---\n\n🚀 **Want more like this?** Every guide, playground, and quiz lives on **[bestpractic.org](https:\u002F\u002Fbestpractic.org\u002F)** — open it and **[sign up free](https:\u002F\u002Fbestpractic.org\u002F)** so the next one finds you.\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)",{"title":108,"canonical":247,"description":248},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls","You shipped dark mode. The page is black, the text is white — and then the date picker opens like a floodlight. color-scheme is the one-line CSS property that tells the browser you","01a09a84-4147-713b-b0e9-a19fc0feb15e",{"id":251,"locked":18},"01a09a84-41e9-75c1-9247-f14b38f4e96e",[253],{"id":45,"slug":46,"title":48,"_count":254},{"questions":51},[256],{"locale":13,"slug":46},{"id":45,"slug":46,"title":48,"_count":258,"questionCount":51},{"questions":51}]