CINXE.COM
GitHub - andreipfeiffer/css-in-js: A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js
<!DOCTYPE html> <html lang="en" data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="true" > <head> <meta charset="utf-8"> <link rel="dns-prefetch" href="https://github.githubassets.com"> <link rel="dns-prefetch" href="https://avatars.githubusercontent.com"> <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com"> <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/"> <link rel="preconnect" href="https://github.githubassets.com" crossorigin> <link rel="preconnect" href="https://avatars.githubusercontent.com"> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-74231a1f3bbb.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-8a995f0bacd4.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-f37fb7684b1f.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-9ac301c3ebe5.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-cd826e8636dc.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-f91b0f603451.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-83beb16e0ecf.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-6e122dab64fc.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-18119e682df0.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-225433424a87.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-aaa714e5674d.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-7eaba1d4847c.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-43ae85d4871b.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-4fce88777fa8.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-0210be90f4d3.css" /> <script type="application/json" id="client-env">{"locale":"en","featureFlags":["a11y_quote_reply_fix","copilot_immersive_issue_preview","copilot_new_references_ui","copilot_chat_repo_custom_instructions_preview","copilot_no_floating_button","copilot_topics_as_references","copilot_read_shared_conversation","copilot_duplicate_thread","copilot_buffered_streaming","dotcom_chat_client_side_skills","experimentation_azure_variant_endpoint","failbot_handle_non_errors","fgpat_form_ui_updates","geojson_azure_maps","ghost_pilot_confidence_truncation_25","ghost_pilot_confidence_truncation_40","github_models_o3_mini_streaming","hovercard_accessibility","insert_before_patch","issues_react_remove_placeholders","issues_react_blur_item_picker_on_close","marketing_pages_search_explore_provider","primer_react_css_modules_ga","react_data_router_pull_requests","remove_child_patch","sample_network_conn_type","swp_enterprise_contact_form","site_proxima_australia_update","viewscreen_sandbox","issues_react_create_milestone","issues_react_cache_fix_workaround","lifecycle_label_name_updates","copilot_task_oriented_assistive_prompts","issues_react_assignee_warning","issue_types_prevent_private_type_creation","refresh_image_video_src","react_router_dispose_on_disconnect","turbo_app_id_restore"]}</script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-f95ccd92d17e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover_js-9da652f58479.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_arianotify-polyfill_ariaNotify-polyfill_js-node_modules_github_mi-3abb8f-46b9f4874d95.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_failbot_failbot_ts-75968cfb5298.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/environment-f04cb2a9fc8c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_primer_behaviors_dist_esm_index_mjs-0dbb79f97f8f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_selector-observer_dist_index_esm_js-f690fd9ae3d5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_relative-time-element_dist_index_js-62d275b7ddd9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_text-expander-element_dist_index_js-78748950cb0c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_auto-complete-element_dist_index_js-node_modules_github_catalyst_-8e9f78-a90ac05d2469.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-b5f1d7-a1760ffda83d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_markdown-toolbar-element_dist_index_js-ceef33f593fa.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_primer_view-co-c44a69-8c52cf4cd0d3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-394f8eb34f19.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-e0a42d158bcc.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_braintree_browser-detection_dist_browser-detection_js-node_modules_githu-2906d7-2a07a295af40.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lit-html_lit-html_js-be8cb88f481b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_morphdom_dist_morphdom-e-7c534c-a4a1922eb55f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_turbo_dist_turbo_es2017-esm_js-a03ee12d659a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-893f9f-b6294cf703b7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_color-convert_index_js-e3180fe3bcb3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_quote-selection_dist_index_js-node_modules_github_session-resume_-947061-e7a6c4a19f98.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_updatable-content_updatable-content_ts-2a55124d5c52.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_task-list_ts-app_assets_modules_github_sso_ts-ui_packages-900dde-768abe60b1f8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_sticky-scroll-into-view_ts-3e000c5d31a9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_ajax-error_ts-app_assets_modules_github_behaviors_include-87a4ae-8be71414579a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_commenting_edit_ts-app_assets_modules_github_behaviors_ht-83c235-e429cff6ceb1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-7ebb6421bf22.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_delegated-events_dist_index_js-node_modules_github_catalyst_lib_index_js-f6223d90c7ba.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-01e85cd1be94.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_virtualized-list_es_index_js-node_modules_github_template-parts_lib_index_js-94dc7a2157c1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-70450e-4b93df70b903.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_ref-selector_ts-3e9d848bab5f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/codespaces-c3bcacfe317c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-3eebbd-0763620ad7bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_decorators_js-node_modules_delegated-events_di-e161aa-9d41fb1b6c9e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_github_remote--3c9c82-b71ef90fbdc7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/repositories-7a0dbaa42c57.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_github_catalyst_lib_inde-dbbea9-26cce2010167.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/code-menu-1c0aedc134b1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-e05a7c4c5398.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-core-aaa76995a864.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-f1bca44e0926.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-cf2f2ab8dab4.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_emotion_is-prop-valid_dist_emotion-is-prop-valid_esm_js-node_modules_emo-62da9f-2df2f32ec596.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_stacktrace-parser_dist_s-e7dcdd-9a233856b02c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover-fn_js-55fea94174bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-58a0c58bfee4.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.e0c9f0687c56358ed85e.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.e0c9f0687c56358ed85e.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <title>GitHub - andreipfeiffer/css-in-js: A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js</title> <meta name="route-pattern" content="/:user_id/:repository" data-turbo-transient> <meta name="route-controller" content="files" data-turbo-transient> <meta name="route-action" content="disambiguate" data-turbo-transient> <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb"> <meta name="request-id" content="E694:127817:493C5F:5411BE:67E25AE1" data-pjax-transient="true"/><meta name="html-safe-nonce" content="69d8997ec98a85a5d85e6b3ba1c668283d700f10e3bafb4a68d6402b9810678c" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFNjk0OjEyNzgxNzo0OTNDNUY6NTQxMUJFOjY3RTI1QUUxIiwidmlzaXRvcl9pZCI6IjQ1NTQ0MzU2ODIzNjc1OTMxODUiLCJyZWdpb25fZWRnZSI6InNvdXRoZWFzdGFzaWEiLCJyZWdpb25fcmVuZGVyIjoic291dGhlYXN0YXNpYSJ9" data-pjax-transient="true"/><meta name="visitor-hmac" content="d44f5b9a28eef3da03e28e2f38e02df078c0109b94363b7677a6a05bab68716b" data-pjax-transient="true"/> <meta name="hovercard-subject-tag" content="repository:327643454" data-turbo-transient> <meta name="github-keyboard-shortcuts" content="repository,copilot" data-turbo-transient="true" /> <meta name="selected-link" value="repo_source" data-turbo-transient> <link rel="assets" href="https://github.githubassets.com/"> <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I"> <meta name="octolytics-url" content="https://collector.github.com/github/collect" /> <meta name="analytics-location" content="/<user-name>/<repo-name>" data-turbo-transient="true" /> <meta name="user-login" content=""> <meta name="viewport" content="width=device-width"> <meta name="description" content="A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js - andreipfeiffer/css-in-js"> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub"> <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub"> <meta property="fb:app_id" content="1401488693436528"> <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/andreipfeiffer/css-in-js" /> <meta name="twitter:image" content="https://opengraph.githubassets.com/c24e1112c88d1dc611e1bf1ee713a28ac5bc481d01eadab378f03df560260746/andreipfeiffer/css-in-js" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="GitHub - andreipfeiffer/css-in-js: A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js" /><meta name="twitter:description" content="A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js - andreipfeiffer/css-in-js" /> <meta property="og:image" content="https://opengraph.githubassets.com/c24e1112c88d1dc611e1bf1ee713a28ac5bc481d01eadab378f03df560260746/andreipfeiffer/css-in-js" /><meta property="og:image:alt" content="A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js - andreipfeiffer/css-in-js" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="GitHub - andreipfeiffer/css-in-js: A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js" /><meta property="og:url" content="https://github.com/andreipfeiffer/css-in-js" /><meta property="og:description" content="A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js - andreipfeiffer/css-in-js" /> <meta name="hostname" content="github.com"> <meta name="expected-hostname" content="github.com"> <meta http-equiv="x-pjax-version" content="0373827985631dee8709153c8c7d01da5e66a3572e60e11a31c7c31e992e814c" data-turbo-track="reload"> <meta http-equiv="x-pjax-csp-version" content="77190eb53eb47fc30bd2fcc17a7eefa2dfd8505869fee9299ba911be3a40a9eb" data-turbo-track="reload"> <meta http-equiv="x-pjax-css-version" content="1994cd18701e16e6efa87d97f308447f5b0f15b7ae2b58d73f3d026c94bd5edd" data-turbo-track="reload"> <meta http-equiv="x-pjax-js-version" content="750eb3203f04d40fb8e86ef127b4d0018d41e873b43fe8b65e463c5a0415a53d" data-turbo-track="reload"> <meta name="turbo-cache-control" content="no-preview" data-turbo-transient=""> <meta data-hydrostats="publish"> <meta name="go-import" content="github.com/andreipfeiffer/css-in-js git https://github.com/andreipfeiffer/css-in-js.git"> <meta name="octolytics-dimension-user_id" content="2570562" /><meta name="octolytics-dimension-user_login" content="andreipfeiffer" /><meta name="octolytics-dimension-repository_id" content="327643454" /><meta name="octolytics-dimension-repository_nwo" content="andreipfeiffer/css-in-js" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="false" /><meta name="octolytics-dimension-repository_network_root_id" content="327643454" /><meta name="octolytics-dimension-repository_network_root_nwo" content="andreipfeiffer/css-in-js" /> <link rel="canonical" href="https://github.com/andreipfeiffer/css-in-js" data-turbo-transient> <meta name="turbo-body-classes" content="logged-out env-production page-responsive"> <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats"> <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors"> <meta name="release" content="7c5ea118ccf070a57cf5fc2458d5cd4c87c0378b"> <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000"> <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png"> <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon"> <meta name="theme-color" content="#1e2327"> <meta name="color-scheme" content="light dark" /> <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials"> </head> <body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div class="position-relative header-wrapper js-header-wrapper "> <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a> <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full"> <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span> </span> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ui-commands_ui-commands_ts-8c874fb594e9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-33dfb803e078.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.e0c9f0687c56358ed85e.module.css" /> <react-partial partial-name="keyboard-shortcuts-dialog" data-ssr="false" data-attempted-ssr="false" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script> <div data-target="react-partial.reactRoot"></div> </react-partial> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-94fd67-4898d1bf4b51.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/sessions-730dca81d0a2.js"></script> <header class="HeaderMktg header-logged-out js-details-container js-header Details f4 py-3" role="banner" data-is-top="true" data-color-mode=light data-light-theme=light data-dark-theme=dark> <h2 class="sr-only">Navigation Menu</h2> <button type="button" class="HeaderMktg-backdrop d-lg-none border-0 position-fixed top-0 left-0 width-full height-full js-details-target" aria-label="Toggle navigation"> <span class="d-none">Toggle navigation</span> </button> <div class="d-flex flex-column flex-lg-row flex-items-center px-3 px-md-4 px-lg-5 height-full position-relative z-1"> <div class="d-flex flex-justify-between flex-items-center width-full width-lg-auto"> <div class="flex-1"> <button aria-label="Toggle navigation" aria-expanded="false" type="button" data-view-component="true" class="js-details-target js-nav-padding-recalculate js-header-menu-toggle Button--link Button--medium Button d-lg-none color-fg-inherit p-1"> <span class="Button-content"> <span class="Button-label"><div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div></span> </span> </button> </div> <a class="mr-lg-3 color-fg-inherit flex-order-2 js-prevent-focus-on-mobile-nav" href="/" aria-label="Homepage" data-analytics-event="{"category":"Marketing nav","action":"click to go to homepage","label":"ref_page:Marketing;ref_cta:Logomark;ref_loc:Header"}"> <svg height="32" aria-hidden="true" viewBox="0 0 24 24" version="1.1" width="32" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path> </svg> </a> <div class="flex-1 flex-order-2 text-right"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Fandreipfeiffer%2Fcss-in-js" class="HeaderMenu-link HeaderMenu-button d-inline-flex d-lg-none flex-order-1 f5 no-underline border color-border-default rounded-2 px-2 py-1 color-fg-inherit js-prevent-focus-on-mobile-nav" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"site header menu","repository_id":null,"auth_type":"SIGN_UP","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="416cb8d9acfcfb6d24a7544f2d0341feb5d5989facdd0621cbf955af78ae51dd" data-analytics-event="{"category":"Marketing nav","action":"click to Sign in","label":"ref_page:Marketing;ref_cta:Sign in;ref_loc:Header"}" > Sign in </a> </div> </div> <div class="HeaderMenu js-header-menu height-fit position-lg-relative d-lg-flex flex-column flex-auto top-0"> <div class="HeaderMenu-wrapper d-flex flex-column flex-self-start flex-lg-row flex-auto rounded rounded-lg-0"> <nav class="HeaderMenu-nav" aria-label="Global"> <ul class="d-lg-flex list-style-none"> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Product <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"github_copilot","context":"product","tag":"link","label":"github_copilot_link_product_navbar"}" href="https://github.com/features/copilot"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Copilot</div> Write better code with AI </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"security","context":"product","tag":"link","label":"security_link_product_navbar"}" href="https://github.com/features/security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">Security</div> Find and fix vulnerabilities </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"actions","context":"product","tag":"link","label":"actions_link_product_navbar"}" href="https://github.com/features/actions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-workflow color-fg-subtle mr-3"> <path d="M1 3a2 2 0 0 1 2-2h6.5a2 2 0 0 1 2 2v6.5a2 2 0 0 1-2 2H7v4.063C7 16.355 7.644 17 8.438 17H12.5v-2.5a2 2 0 0 1 2-2H21a2 2 0 0 1 2 2V21a2 2 0 0 1-2 2h-6.5a2 2 0 0 1-2-2v-2.5H8.437A2.939 2.939 0 0 1 5.5 15.562V11.5H3a2 2 0 0 1-2-2Zm2-.5a.5.5 0 0 0-.5.5v6.5a.5.5 0 0 0 .5.5h6.5a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5ZM14.5 14a.5.5 0 0 0-.5.5V21a.5.5 0 0 0 .5.5H21a.5.5 0 0 0 .5-.5v-6.5a.5.5 0 0 0-.5-.5Z"></path> </svg> <div> <div class="color-fg-default h4">Actions</div> Automate any workflow </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"codespaces","context":"product","tag":"link","label":"codespaces_link_product_navbar"}" href="https://github.com/features/codespaces"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-codespaces color-fg-subtle mr-3"> <path d="M3.5 3.75C3.5 2.784 4.284 2 5.25 2h13.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 18.75 13H5.25a1.75 1.75 0 0 1-1.75-1.75Zm-2 12c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v4a1.75 1.75 0 0 1-1.75 1.75H3.25a1.75 1.75 0 0 1-1.75-1.75ZM5.25 3.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h13.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Zm-2 12a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h17.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25Z"></path><path d="M10 17.75a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> <div> <div class="color-fg-default h4">Codespaces</div> Instant dev environments </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"issues","context":"product","tag":"link","label":"issues_link_product_navbar"}" href="https://github.com/features/issues"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-issue-opened color-fg-subtle mr-3"> <path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Zm9.5 2a2 2 0 1 1-.001-3.999A2 2 0 0 1 12 14Z"></path> </svg> <div> <div class="color-fg-default h4">Issues</div> Plan and track work </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"code_review","context":"product","tag":"link","label":"code_review_link_product_navbar"}" href="https://github.com/features/code-review"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-review color-fg-subtle mr-3"> <path d="M10.3 6.74a.75.75 0 0 1-.04 1.06l-2.908 2.7 2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M1.5 4.25c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v12.5a1.75 1.75 0 0 1-1.75 1.75h-9.69l-3.573 3.573A1.458 1.458 0 0 1 5 21.043V18.5H3.25a1.75 1.75 0 0 1-1.75-1.75ZM3.25 4a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 .75.75v3.19l3.72-3.72a.749.749 0 0 1 .53-.22h10a.25.25 0 0 0 .25-.25V4.25a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Review</div> Manage code changes </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"discussions","context":"product","tag":"link","label":"discussions_link_product_navbar"}" href="https://github.com/features/discussions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Discussions</div> Collaborate outside of code </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"code_search","context":"product","tag":"link","label":"code_search_link_product_navbar"}" href="https://github.com/features/code-search"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-square color-fg-subtle mr-3"> <path d="M10.3 8.24a.75.75 0 0 1-.04 1.06L7.352 12l2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M2 3.75C2 2.784 2.784 2 3.75 2h16.5c.966 0 1.75.784 1.75 1.75v16.5A1.75 1.75 0 0 1 20.25 22H3.75A1.75 1.75 0 0 1 2 20.25Zm1.75-.25a.25.25 0 0 0-.25.25v16.5c0 .138.112.25.25.25h16.5a.25.25 0 0 0 .25-.25V3.75a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Search</div> Find more, search less </div> </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="product-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="product-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"all_features","context":"product","tag":"link","label":"all_features_link_product_navbar"}" href="https://github.com/features"> All features </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"documentation","context":"product","tag":"link","label":"documentation_link_product_navbar"}" href="https://docs.github.com"> Documentation <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"github_skills","context":"product","tag":"link","label":"github_skills_link_product_navbar"}" href="https://skills.github.com"> GitHub Skills <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"blog","context":"product","tag":"link","label":"blog_link_product_navbar"}" href="https://github.blog"> Blog <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Solutions <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 pb-lg-3 mb-3 mb-lg-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-company-size-heading">By company size</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-company-size-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"enterprises","context":"solutions","tag":"link","label":"enterprises_link_solutions_navbar"}" href="https://github.com/enterprise"> Enterprises </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"small_and_medium_teams","context":"solutions","tag":"link","label":"small_and_medium_teams_link_solutions_navbar"}" href="https://github.com/team"> Small and medium teams </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"startups","context":"solutions","tag":"link","label":"startups_link_solutions_navbar"}" href="https://github.com/enterprise/startups"> Startups </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"nonprofits","context":"solutions","tag":"link","label":"nonprofits_link_solutions_navbar"}" href="/solutions/industry/nonprofits"> Nonprofits </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-use-case-heading">By use case</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-use-case-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"devsecops","context":"solutions","tag":"link","label":"devsecops_link_solutions_navbar"}" href="/solutions/use-case/devsecops"> DevSecOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"devops","context":"solutions","tag":"link","label":"devops_link_solutions_navbar"}" href="/solutions/use-case/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"ci_cd","context":"solutions","tag":"link","label":"ci_cd_link_solutions_navbar"}" href="/solutions/use-case/ci-cd"> CI/CD </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"view_all_use_cases","context":"solutions","tag":"link","label":"view_all_use_cases_link_solutions_navbar"}" href="/solutions/use-case"> View all use cases </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-industry-heading">By industry</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-industry-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"healthcare","context":"solutions","tag":"link","label":"healthcare_link_solutions_navbar"}" href="/solutions/industry/healthcare"> Healthcare </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"financial_services","context":"solutions","tag":"link","label":"financial_services_link_solutions_navbar"}" href="/solutions/industry/financial-services"> Financial services </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"manufacturing","context":"solutions","tag":"link","label":"manufacturing_link_solutions_navbar"}" href="/solutions/industry/manufacturing"> Manufacturing </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"government","context":"solutions","tag":"link","label":"government_link_solutions_navbar"}" href="/solutions/industry/government"> Government </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"view_all_industries","context":"solutions","tag":"link","label":"view_all_industries_link_solutions_navbar"}" href="/solutions/industry"> View all industries </a></li> </ul> </div> </div> <div class="HeaderMenu-trailing-link rounded-bottom-2 flex-shrink-0 mt-lg-4 px-lg-4 py-4 py-lg-3 f5 text-semibold"> <a href="/solutions"> View all solutions <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-right HeaderMenu-trailing-link-icon"> <path d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z"></path> </svg> </a> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Resources <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-topics-heading">Topics</span> <ul class="list-style-none f5" aria-labelledby="resources-topics-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"ai","context":"resources","tag":"link","label":"ai_link_resources_navbar"}" href="/resources/articles/ai"> AI </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"devops","context":"resources","tag":"link","label":"devops_link_resources_navbar"}" href="/resources/articles/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"security","context":"resources","tag":"link","label":"security_link_resources_navbar"}" href="/resources/articles/security"> Security </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"software_development","context":"resources","tag":"link","label":"software_development_link_resources_navbar"}" href="/resources/articles/software-development"> Software Development </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"view_all","context":"resources","tag":"link","label":"view_all_link_resources_navbar"}" href="/resources/articles"> View all </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="resources-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"learning_pathways","context":"resources","tag":"link","label":"learning_pathways_link_resources_navbar"}" href="https://resources.github.com/learn/pathways"> Learning Pathways <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"events_amp_webinars","context":"resources","tag":"link","label":"events_amp_webinars_link_resources_navbar"}" href="https://resources.github.com"> Events & Webinars <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"ebooks_amp_whitepapers","context":"resources","tag":"link","label":"ebooks_amp_whitepapers_link_resources_navbar"}" href="https://github.com/resources/whitepapers"> Ebooks & Whitepapers </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"customer_stories","context":"resources","tag":"link","label":"customer_stories_link_resources_navbar"}" href="https://github.com/customer-stories"> Customer Stories </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"partners","context":"resources","tag":"link","label":"partners_link_resources_navbar"}" href="https://partner.github.com"> Partners <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"executive_insights","context":"resources","tag":"link","label":"executive_insights_link_resources_navbar"}" href="https://github.com/solutions/executive-insights"> Executive Insights </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Open Source <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"github_sponsors","context":"open_source","tag":"link","label":"github_sponsors_link_open_source_navbar"}" href="/sponsors"> <div> <div class="color-fg-default h4">GitHub Sponsors</div> Fund open source developers </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"the_readme_project","context":"open_source","tag":"link","label":"the_readme_project_link_open_source_navbar"}" href="https://github.com/readme"> <div> <div class="color-fg-default h4">The ReadME Project</div> GitHub community articles </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="open-source-repositories-heading">Repositories</span> <ul class="list-style-none f5" aria-labelledby="open-source-repositories-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"topics","context":"open_source","tag":"link","label":"topics_link_open_source_navbar"}" href="https://github.com/topics"> Topics </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"trending","context":"open_source","tag":"link","label":"trending_link_open_source_navbar"}" href="https://github.com/trending"> Trending </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"collections","context":"open_source","tag":"link","label":"collections_link_open_source_navbar"}" href="https://github.com/collections"> Collections </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Enterprise <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"enterprise_platform","context":"enterprise","tag":"link","label":"enterprise_platform_link_enterprise_navbar"}" href="/enterprise"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-stack color-fg-subtle mr-3"> <path d="M11.063 1.456a1.749 1.749 0 0 1 1.874 0l8.383 5.316a1.751 1.751 0 0 1 0 2.956l-8.383 5.316a1.749 1.749 0 0 1-1.874 0L2.68 9.728a1.751 1.751 0 0 1 0-2.956Zm1.071 1.267a.25.25 0 0 0-.268 0L3.483 8.039a.25.25 0 0 0 0 .422l8.383 5.316a.25.25 0 0 0 .268 0l8.383-5.316a.25.25 0 0 0 0-.422Z"></path><path d="M1.867 12.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path><path d="M1.867 16.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path> </svg> <div> <div class="color-fg-default h4">Enterprise platform</div> AI-powered developer platform </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="enterprise-available-add-ons-heading">Available add-ons</span> <ul class="list-style-none f5" aria-labelledby="enterprise-available-add-ons-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"advanced_security","context":"enterprise","tag":"link","label":"advanced_security_link_enterprise_navbar"}" href="https://github.com/enterprise/advanced-security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">Advanced Security</div> Enterprise-grade security features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"copilot_for_business","context":"enterprise","tag":"link","label":"copilot_for_business_link_enterprise_navbar"}" href="/features/copilot/copilot-business"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">Copilot for business</div> Enterprise-grade AI features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"premium_support","context":"enterprise","tag":"link","label":"premium_support_link_enterprise_navbar"}" href="/premium-support"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Premium Support</div> Enterprise-grade 24/7 support </div> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <a class="HeaderMenu-link no-underline px-0 px-lg-2 py-3 py-lg-2 d-block d-lg-inline-block" data-analytics-event="{"location":"navbar","action":"pricing","context":"global","tag":"link","label":"pricing_link_global_navbar"}" href="https://github.com/pricing">Pricing</a> </li> </ul> </nav> <div class="d-flex flex-column flex-lg-row width-full flex-justify-end flex-lg-items-center text-center mt-3 mt-lg-0 text-lg-left ml-lg-3"> <qbsearch-input class="search-input" data-scope="repo:andreipfeiffer/css-in-js" data-custom-scopes-path="/search/custom_scopes" data-delete-custom-scopes-csrf="FLxQreNEGcz5mrR1P5RS8i6FRrmTnMP09t-8Q86Fuk4JxbvOAEYgimirYrbj2gN-VzEIZc59jI-LraPuLC514g" data-max-custom-scopes="10" data-header-redesign-enabled="false" data-initial-value="" data-blackbird-suggestions-path="/search/suggestions" data-jump-to-suggestions-path="/_graphql/GetSuggestedNavigationDestinations" data-current-repository="andreipfeiffer/css-in-js" data-current-org="" data-current-owner="andreipfeiffer" data-logged-in="false" data-copilot-chat-enabled="false" data-nl-search-enabled="false" data-retain-scroll-position="true"> <div class="search-input-container search-with-dialog position-relative d-flex flex-row flex-items-center mr-4 rounded" data-action="click:qbsearch-input#searchInputContainerClicked" > <button type="button" class="header-search-button placeholder input-button form-control d-flex flex-1 flex-self-stretch flex-items-center no-wrap width-full py-0 pl-2 pr-0 text-left border-0 box-shadow-none" data-target="qbsearch-input.inputButton" aria-label="Search or jump to…" aria-haspopup="dialog" placeholder="Search or jump to..." data-hotkey=s,/ autocapitalize="off" data-analytics-event="{"location":"navbar","action":"searchbar","context":"global","tag":"input","label":"searchbar_input_global_navbar"}" data-action="click:qbsearch-input#handleExpand" > <div class="mr-2 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </div> <span class="flex-1" data-target="qbsearch-input.inputButtonText">Search or jump to...</span> <div class="d-flex" data-target="qbsearch-input.hotkeyIndicator"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="20" aria-hidden="true" class="mr-1"><path fill="none" stroke="#979A9C" opacity=".4" d="M3.5.5h12c1.7 0 3 1.3 3 3v13c0 1.7-1.3 3-3 3h-12c-1.7 0-3-1.3-3-3v-13c0-1.7 1.3-3 3-3z"></path><path fill="#979A9C" d="M11.8 6L8 15.1h-.9L10.8 6h1z"></path></svg> </div> </button> <input type="hidden" name="type" class="js-site-search-type-field"> <div class="Overlay--hidden " data-modal-dialog-overlay> <modal-dialog data-action="close:qbsearch-input#handleClose cancel:qbsearch-input#handleClose" data-target="qbsearch-input.searchSuggestionsDialog" role="dialog" id="search-suggestions-dialog" aria-modal="true" aria-labelledby="search-suggestions-dialog-header" data-view-component="true" class="Overlay Overlay--width-large Overlay--height-auto"> <h1 id="search-suggestions-dialog-header" class="sr-only">Search code, repositories, users, issues, pull requests...</h1> <div class="Overlay-body Overlay-body--paddingNone"> <div data-view-component="true"> <div class="search-suggestions position-fixed width-full color-shadow-large border color-fg-default color-bg-default overflow-hidden d-flex flex-column query-builder-container" style="border-radius: 12px;" data-target="qbsearch-input.queryBuilderContainer" hidden > <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="query-builder-test-form" action="" accept-charset="UTF-8" method="get"> <query-builder data-target="qbsearch-input.queryBuilder" id="query-builder-query-builder-test" data-filter-key=":" data-view-component="true" class="QueryBuilder search-query-builder"> <div class="FormControl FormControl--fullWidth"> <label id="query-builder-test-label" for="query-builder-test" class="FormControl-label sr-only"> Search </label> <div class="QueryBuilder-StyledInput width-fit " data-target="query-builder.styledInput" > <span id="query-builder-test-leadingvisual-wrap" class="FormControl-input-leadingVisualWrap QueryBuilder-leadingVisualWrap"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search FormControl-input-leadingVisual"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </span> <div data-target="query-builder.styledInputContainer" class="QueryBuilder-StyledInputContainer"> <div aria-hidden="true" class="QueryBuilder-StyledInputContent" data-target="query-builder.styledInputContent" ></div> <div class="QueryBuilder-InputWrapper"> <div aria-hidden="true" class="QueryBuilder-Sizer" data-target="query-builder.sizer"></div> <input id="query-builder-test" name="query-builder-test" value="" autocomplete="off" type="text" role="combobox" spellcheck="false" aria-expanded="false" aria-describedby="validation-47f3d335-a3ee-4b60-b926-3b78ce2c20ef" data-target="query-builder.input" data-action=" input:query-builder#inputChange blur:query-builder#inputBlur keydown:query-builder#inputKeydown focus:query-builder#inputFocus " data-view-component="true" class="FormControl-input QueryBuilder-Input FormControl-medium" /> </div> </div> <span class="sr-only" id="query-builder-test-clear">Clear</span> <button role="button" id="query-builder-test-clear-button" aria-labelledby="query-builder-test-clear query-builder-test-label" data-target="query-builder.clearButton" data-action=" click:query-builder#clear focus:query-builder#clearButtonFocus blur:query-builder#clearButtonBlur " variant="small" hidden="hidden" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium mr-1 px-2 py-0 d-flex flex-items-center rounded-1 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x-circle-fill Button-visual"> <path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path> </svg> </button> </div> <template id="search-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </template> <template id="code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="file-code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-file-code"> <path d="M4 1.75C4 .784 4.784 0 5.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 14.25 15h-9a.75.75 0 0 1 0-1.5h9a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 10 4.25V1.5H5.75a.25.25 0 0 0-.25.25v2.5a.75.75 0 0 1-1.5 0Zm1.72 4.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l1.47-1.47-1.47-1.47a.75.75 0 0 1 0-1.06ZM3.28 7.78 1.81 9.25l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Zm8.22-6.218V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path> </svg> </template> <template id="history-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-history"> <path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path> </svg> </template> <template id="repo-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> </template> <template id="bookmark-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bookmark"> <path d="M3 2.75C3 1.784 3.784 1 4.75 1h6.5c.966 0 1.75.784 1.75 1.75v11.5a.75.75 0 0 1-1.227.579L8 11.722l-3.773 3.107A.751.751 0 0 1 3 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.91l3.023-2.489a.75.75 0 0 1 .954 0l3.023 2.49V2.75a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="plus-circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-plus-circle"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25v2.5h2.5a.75.75 0 0 1 0 1.5h-2.5v2.5a.75.75 0 0 1-1.5 0v-2.5h-2.5a.75.75 0 0 1 0-1.5h2.5v-2.5a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> </template> <template id="trash-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-trash"> <path d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z"></path> </svg> </template> <template id="team-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-people"> <path d="M2 5.5a3.5 3.5 0 1 1 5.898 2.549 5.508 5.508 0 0 1 3.034 4.084.75.75 0 1 1-1.482.235 4 4 0 0 0-7.9 0 .75.75 0 0 1-1.482-.236A5.507 5.507 0 0 1 3.102 8.05 3.493 3.493 0 0 1 2 5.5ZM11 4a3.001 3.001 0 0 1 2.22 5.018 5.01 5.01 0 0 1 2.56 3.012.749.749 0 0 1-.885.954.752.752 0 0 1-.549-.514 3.507 3.507 0 0 0-2.522-2.372.75.75 0 0 1-.574-.73v-.352a.75.75 0 0 1 .416-.672A1.5 1.5 0 0 0 11 5.5.75.75 0 0 1 11 4Zm-5.5-.5a2 2 0 1 0-.001 3.999A2 2 0 0 0 5.5 3.5Z"></path> </svg> </template> <template id="project-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-project"> <path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25ZM11.75 3a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-1.5 0v-7.5a.75.75 0 0 1 .75-.75Zm-8.25.75a.75.75 0 0 1 1.5 0v5.5a.75.75 0 0 1-1.5 0ZM8 3a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 3Z"></path> </svg> </template> <template id="pencil-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pencil"> <path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path> </svg> </template> <template id="copilot-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot"> <path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="copilot-error-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot-error"> <path d="M16 11.24c0 .112-.072.274-.21.467L13 9.688V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-.198 0-.388-.009-.571-.029L6.833 5.226a4.01 4.01 0 0 0 .17-.782c.117-.935-.037-1.395-.241-1.614-.193-.206-.637-.413-1.682-.297-.683.076-1.115.231-1.395.415l-1.257-.91c.579-.564 1.413-.877 2.485-.996 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095Zm-5.083-8.707c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Zm2.511 11.074c-1.393.776-3.272 1.428-5.43 1.428-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.18-.455-.241-.963-.252-1.475L.31 4.107A.747.747 0 0 1 0 3.509V3.49a.748.748 0 0 1 .625-.73c.156-.026.306.047.435.139l14.667 10.578a.592.592 0 0 1 .227.264.752.752 0 0 1 .046.249v.022a.75.75 0 0 1-1.19.596Zm-1.367-.991L5.635 7.964a5.128 5.128 0 0 1-.889.073c-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433 1.539 0 3.089-.505 4.063-.934Z"></path> </svg> </template> <template id="workflow-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-workflow"> <path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="book-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> </template> <template id="code-review-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-review"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 13H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25v-8.5C0 1.784.784 1 1.75 1ZM1.5 2.75v8.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm5.28 1.72a.75.75 0 0 1 0 1.06L5.31 7l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.75.75 0 0 1 1.06 0Zm2.44 0a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L10.69 7 9.22 5.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="codespaces-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-codespaces"> <path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> </template> <template id="comment-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment"> <path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="comment-discussion-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment-discussion"> <path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path> </svg> </template> <template id="organization-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-organization"> <path d="M1.75 16A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0h8.5C11.216 0 12 .784 12 1.75v12.5c0 .085-.006.168-.018.25h2.268a.25.25 0 0 0 .25-.25V8.285a.25.25 0 0 0-.111-.208l-1.055-.703a.749.749 0 1 1 .832-1.248l1.055.703c.487.325.779.871.779 1.456v5.965A1.75 1.75 0 0 1 14.25 16h-3.5a.766.766 0 0 1-.197-.026c-.099.017-.2.026-.303.026h-3a.75.75 0 0 1-.75-.75V14h-1v1.25a.75.75 0 0 1-.75.75Zm-.25-1.75c0 .138.112.25.25.25H4v-1.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 .75.75v1.25h2.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM3.75 6h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 3.75A.75.75 0 0 1 3.75 3h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 3.75Zm4 3A.75.75 0 0 1 7.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 7 6.75ZM7.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 9.75A.75.75 0 0 1 3.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 9.75ZM7.75 9h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="rocket-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-rocket"> <path d="M14.064 0h.186C15.216 0 16 .784 16 1.75v.186a8.752 8.752 0 0 1-2.564 6.186l-.458.459c-.314.314-.641.616-.979.904v3.207c0 .608-.315 1.172-.833 1.49l-2.774 1.707a.749.749 0 0 1-1.11-.418l-.954-3.102a1.214 1.214 0 0 1-.145-.125L3.754 9.816a1.218 1.218 0 0 1-.124-.145L.528 8.717a.749.749 0 0 1-.418-1.11l1.71-2.774A1.748 1.748 0 0 1 3.31 4h3.204c.288-.338.59-.665.904-.979l.459-.458A8.749 8.749 0 0 1 14.064 0ZM8.938 3.623h-.002l-.458.458c-.76.76-1.437 1.598-2.02 2.5l-1.5 2.317 2.143 2.143 2.317-1.5c.902-.583 1.74-1.26 2.499-2.02l.459-.458a7.25 7.25 0 0 0 2.123-5.127V1.75a.25.25 0 0 0-.25-.25h-.186a7.249 7.249 0 0 0-5.125 2.123ZM3.56 14.56c-.732.732-2.334 1.045-3.005 1.148a.234.234 0 0 1-.201-.064.234.234 0 0 1-.064-.201c.103-.671.416-2.273 1.15-3.003a1.502 1.502 0 1 1 2.12 2.12Zm6.94-3.935c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213ZM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </template> <template id="shield-check-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield-check"> <path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="heart-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-heart"> <path d="m8 14.25.345.666a.75.75 0 0 1-.69 0l-.008-.004-.018-.01a7.152 7.152 0 0 1-.31-.17 22.055 22.055 0 0 1-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.066 22.066 0 0 1-3.744 2.584l-.018.01-.006.003h-.002ZM4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.58 20.58 0 0 0 8 13.393a20.58 20.58 0 0 0 3.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.749.749 0 0 1-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5Z"></path> </svg> </template> <template id="server-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-server"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v4c0 .372-.116.717-.314 1 .198.283.314.628.314 1v4a1.75 1.75 0 0 1-1.75 1.75H1.75A1.75 1.75 0 0 1 0 12.75v-4c0-.358.109-.707.314-1a1.739 1.739 0 0 1-.314-1v-4C0 1.784.784 1 1.75 1ZM1.5 2.75v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm.25 5.75a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25ZM7 4.75A.75.75 0 0 1 7.75 4h4.5a.75.75 0 0 1 0 1.5h-4.5A.75.75 0 0 1 7 4.75ZM7.75 10h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM3 4.75A.75.75 0 0 1 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 4.75ZM3.75 10h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="globe-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-globe"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM5.78 8.75a9.64 9.64 0 0 0 1.363 4.177c.255.426.542.832.857 1.215.245-.296.551-.705.857-1.215A9.64 9.64 0 0 0 10.22 8.75Zm4.44-1.5a9.64 9.64 0 0 0-1.363-4.177c-.307-.51-.612-.919-.857-1.215a9.927 9.927 0 0 0-.857 1.215A9.64 9.64 0 0 0 5.78 7.25Zm-5.944 1.5H1.543a6.507 6.507 0 0 0 4.666 5.5c-.123-.181-.24-.365-.352-.552-.715-1.192-1.437-2.874-1.581-4.948Zm-2.733-1.5h2.733c.144-2.074.866-3.756 1.58-4.948.12-.197.237-.381.353-.552a6.507 6.507 0 0 0-4.666 5.5Zm10.181 1.5c-.144 2.074-.866 3.756-1.58 4.948-.12.197-.237.381-.353.552a6.507 6.507 0 0 0 4.666-5.5Zm2.733-1.5a6.507 6.507 0 0 0-4.666-5.5c.123.181.24.365.353.552.714 1.192 1.436 2.874 1.58 4.948Z"></path> </svg> </template> <template id="issue-opened-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </template> <template id="device-mobile-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-mobile"> <path d="M3.75 0h8.5C13.216 0 14 .784 14 1.75v12.5A1.75 1.75 0 0 1 12.25 16h-8.5A1.75 1.75 0 0 1 2 14.25V1.75C2 .784 2.784 0 3.75 0ZM3.5 1.75v12.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM8 13a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path> </svg> </template> <template id="package-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-package"> <path d="m8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.201.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432Zm6.25 8.271 4.625-2.683a.25.25 0 0 0 .125-.216V5.677L8.75 8.432Z"></path> </svg> </template> <template id="credit-card-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-credit-card"> <path d="M10.75 9a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-1.5Z"></path><path d="M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25ZM14.5 6.5h-13v5.75c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25Zm0-2.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25V5h13Z"></path> </svg> </template> <template id="play-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </template> <template id="gift-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-gift"> <path d="M2 2.75A2.75 2.75 0 0 1 4.75 0c.983 0 1.873.42 2.57 1.232.268.318.497.668.68 1.042.183-.375.411-.725.68-1.044C9.376.42 10.266 0 11.25 0a2.75 2.75 0 0 1 2.45 4h.55c.966 0 1.75.784 1.75 1.75v2c0 .698-.409 1.301-1 1.582v4.918A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25V9.332C.409 9.05 0 8.448 0 7.75v-2C0 4.784.784 4 1.75 4h.55c-.192-.375-.3-.8-.3-1.25ZM7.25 9.5H2.5v4.75c0 .138.112.25.25.25h4.5Zm1.5 0v5h4.5a.25.25 0 0 0 .25-.25V9.5Zm0-4V8h5.5a.25.25 0 0 0 .25-.25v-2a.25.25 0 0 0-.25-.25Zm-7 0a.25.25 0 0 0-.25.25v2c0 .138.112.25.25.25h5.5V5.5h-5.5Zm3-4a1.25 1.25 0 0 0 0 2.5h2.309c-.233-.818-.542-1.401-.878-1.793-.43-.502-.915-.707-1.431-.707ZM8.941 4h2.309a1.25 1.25 0 0 0 0-2.5c-.516 0-1 .205-1.43.707-.337.392-.646.975-.879 1.793Z"></path> </svg> </template> <template id="code-square-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-square"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="device-desktop-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-desktop"> <path d="M14.25 1c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 14.25 12h-3.727c.099 1.041.52 1.872 1.292 2.757A.752.752 0 0 1 11.25 16h-6.5a.75.75 0 0 1-.565-1.243c.772-.885 1.192-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5C0 1.784.784 1 1.75 1ZM1.75 2.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25ZM9.018 12H6.982a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5Z"></path> </svg> </template> <div class="position-relative"> <ul role="listbox" class="ActionListWrap QueryBuilder-ListWrap" aria-label="Suggestions" data-action=" combobox-commit:query-builder#comboboxCommit mousedown:query-builder#resultsMousedown " data-target="query-builder.resultsList" data-persist-list=false id="query-builder-test-results" ></ul> </div> <div class="FormControl-inlineValidation" id="validation-47f3d335-a3ee-4b60-b926-3b78ce2c20ef" hidden="hidden"> <span class="FormControl-inlineValidation--visual"> <svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill"> <path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path> </svg> </span> <span></span> </div> </div> <div data-target="query-builder.screenReaderFeedback" aria-live="polite" aria-atomic="true" class="sr-only"></div> </query-builder></form> <div class="d-flex flex-row color-fg-muted px-3 text-small color-bg-default search-feedback-prompt"> <a target="_blank" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax" data-view-component="true" class="Link color-fg-accent text-normal ml-2">Search syntax tips</a> <div class="d-flex flex-1"></div> </div> </div> </div> </div> </modal-dialog></div> </div> <div data-action="click:qbsearch-input#retract" class="dark-backdrop position-fixed" hidden data-target="qbsearch-input.darkBackdrop"></div> <div class="color-fg-default"> <dialog-helper> <dialog data-target="qbsearch-input.feedbackDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="feedback-dialog" aria-modal="true" aria-labelledby="feedback-dialog-title" aria-describedby="feedback-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="feedback-dialog-title"> Provide feedback </h1> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="feedback-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="feedback-dialog-title"> <div data-view-component="true" class="Overlay-body"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="code-search-feedback-form" data-turbo="false" action="/search/feedback" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="ZEY90pD1tbbRYTkgLdTxyAkDZFimu6KGRgbpiKx0lLIoQ+2i5nHbEbbvJm8sGfRQgDucWoDyBL30PzHX2L4KRw==" /> <p>We read every piece of feedback, and take your input very seriously.</p> <textarea name="feedback" class="form-control width-full mb-2" style="height: 120px" id="feedback"></textarea> <input name="include_email" id="include_email" aria-label="Include my email address so I can be contacted" class="form-control mr-2" type="checkbox"> <label for="include_email" style="font-weight: normal">Include my email address so I can be contacted</label> </form></div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd"> <button data-close-dialog-id="feedback-dialog" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="code-search-feedback-form" data-action="click:qbsearch-input#submitFeedback" type="submit" data-view-component="true" class="btn-primary btn"> Submit feedback </button> </div> </dialog></dialog-helper> <custom-scopes data-target="qbsearch-input.customScopesManager"> <dialog-helper> <dialog data-target="custom-scopes.customScopesModalDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="custom-scopes-dialog" aria-modal="true" aria-labelledby="custom-scopes-dialog-title" aria-describedby="custom-scopes-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header Overlay-header--divided"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="custom-scopes-dialog-title"> Saved searches </h1> <h2 id="custom-scopes-dialog-description" class="Overlay-description">Use saved searches to filter your results more quickly</h2> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="custom-scopes-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="custom-scopes-dialog-title"> <div data-view-component="true" class="Overlay-body"> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <div hidden class="create-custom-scope-form" data-target="custom-scopes.createCustomScopeForm"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="custom-scopes-dialog-form" data-turbo="false" action="/search/custom_scopes" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="jZKFw3MDXq8CLgrFvsEY4GKNl/GTHEbymuMshnGbnTDVuv3UUGRZ+X8wVR8O9gpdXRC26kfpUqGR+Y8pcI8u1w==" /> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <input type="hidden" id="custom_scope_id" name="custom_scope_id" data-target="custom-scopes.customScopesIdField"> <div class="form-group"> <label for="custom_scope_name">Name</label> <auto-check src="/search/custom_scopes/check_name" required only-validate-on-blur="false"> <input type="text" name="custom_scope_name" id="custom_scope_name" data-target="custom-scopes.customScopesNameField" class="form-control" autocomplete="off" placeholder="github-ruby" required maxlength="50"> <input type="hidden" data-csrf="true" value="x73jn9/hcd2yjQ9MoHxEr4/z7f3af3E3gwkgUDHKQih75L5ASLIVuQ8aX2WtDPJYcEkj4uab60APTUelbe3YxA==" /> </auto-check> </div> <div class="form-group"> <label for="custom_scope_query">Query</label> <input type="text" name="custom_scope_query" id="custom_scope_query" data-target="custom-scopes.customScopesQueryField" class="form-control" autocomplete="off" placeholder="(repo:mona/a OR repo:mona/b) AND lang:python" required maxlength="500"> </div> <p class="text-small color-fg-muted"> To see all available qualifiers, see our <a class="Link--inTextBlock" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax">documentation</a>. </p> </form> </div> <div data-target="custom-scopes.manageCustomScopesForm"> <div data-target="custom-scopes.list"></div> </div> </div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd Overlay-footer--divided"> <button data-action="click:custom-scopes#customScopesCancel" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="custom-scopes-dialog-form" data-action="click:custom-scopes#customScopesSubmit" data-target="custom-scopes.customScopesSubmitButton" type="submit" data-view-component="true" class="btn-primary btn"> Create saved search </button> </div> </dialog></dialog-helper> </custom-scopes> </div> </qbsearch-input> <div class="position-relative HeaderMenu-link-wrap d-lg-inline-block"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Fandreipfeiffer%2Fcss-in-js" class="HeaderMenu-link HeaderMenu-link--sign-in HeaderMenu-button flex-shrink-0 no-underline d-none d-lg-inline-flex border border-lg-0 rounded rounded-lg-0 px-2 py-1" style="margin-left: 12px;" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"site header menu","repository_id":null,"auth_type":"SIGN_UP","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="416cb8d9acfcfb6d24a7544f2d0341feb5d5989facdd0621cbf955af78ae51dd" data-analytics-event="{"category":"Marketing nav","action":"click to go to homepage","label":"ref_page:Marketing;ref_cta:Sign in;ref_loc:Header"}" > Sign in </a> </div> <a href="/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=andreipfeiffer%2Fcss-in-js" class="HeaderMenu-link HeaderMenu-link--sign-up HeaderMenu-button flex-shrink-0 d-flex d-lg-inline-flex no-underline border color-border-default rounded px-2 py-1" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"site header menu","repository_id":null,"auth_type":"SIGN_UP","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="416cb8d9acfcfb6d24a7544f2d0341feb5d5989facdd0621cbf955af78ae51dd" data-analytics-event="{"category":"Sign up","action":"click to sign up for account","label":"ref_page:/<user-name>/<repo-name>;ref_cta:Sign up;ref_loc:header logged out"}" > Sign up </a> <button type="button" class="sr-only js-header-menu-focus-trap d-block d-lg-none">Reseting focus</button> </div> </div> </div> </div> </header> <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <button id="icon-button-a3d5ddd3-17ef-4b58-ac4e-c609ab864934" aria-labelledby="tooltip-d20246c9-0304-4382-b7b3-d0cf68c92910" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button><tool-tip id="tooltip-d20246c9-0304-4382-b7b3-d0cf68c92910" for="icon-button-a3d5ddd3-17ef-4b58-ac4e-c609ab864934" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip> </div> </div> <div id="start-of-content" class="show-on-focus"></div> <div id="js-flash-container" class="flash-container" data-turbo-replace> <template class="js-flash-template"> <div class="flash flash-full {{ className }}"> <div > <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div aria-atomic="true" role="alert" class="js-flash-alert"> <div>{{ message }}</div> </div> </div> </div> </template> </div> <div class="application-main " data-commit-hovercards-enabled data-discussion-hovercards-enabled data-issue-and-pr-hovercards-enabled data-project-hovercards-enabled > <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class=""> <main id="js-repo-pjax-container" > <div id="repository-container-header" class="pt-3 hide-full-screen" style="background-color: var(--page-header-bgColor, var(--color-page-header-bg));" data-turbo-replace> <div class="d-flex flex-nowrap flex-justify-end mb-3 px-3 px-lg-5" style="gap: 1rem;"> <div class="flex-auto min-width-0 width-fit"> <div class=" d-flex flex-wrap flex-items-center wb-break-word f3 text-normal"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo color-fg-muted mr-2"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> <span class="author flex-self-stretch" itemprop="author"> <a class="url fn" rel="author" data-hovercard-type="user" data-hovercard-url="/users/andreipfeiffer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/andreipfeiffer"> andreipfeiffer </a> </span> <span class="mx-1 flex-self-stretch color-fg-muted">/</span> <strong itemprop="name" class="mr-2 flex-self-stretch"> <a data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/andreipfeiffer/css-in-js">css-in-js</a> </strong> <span></span><span class="Label Label--secondary v-align-middle mr-1">Public</span> </div> </div> <div id="repository-details-container" class="flex-shrink-0" data-turbo-replace style="max-width: 70%;"> <ul class="pagehead-actions flex-shrink-0 d-none d-md-inline" style="padding: 2px 0;"> <li> <a href="/login?return_to=%2Fandreipfeiffer%2Fcss-in-js" rel="nofollow" id="repository-details-watch-button" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"notification subscription menu watch","repository_id":null,"auth_type":"LOG_IN","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="1fceca7577de1f3406456e4063137ea61a3ebf6addf9169bd6bfa05e5d26c8b8" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-ce1ee02d-64ec-4fb6-b38a-30c305aa8d3c" for="repository-details-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </li> <li> <a icon="repo-forked" id="fork-button" href="/login?return_to=%2Fandreipfeiffer%2Fcss-in-js" rel="nofollow" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"repo details fork button","repository_id":327643454,"auth_type":"LOG_IN","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="ec30e365d211c311af4990e447c859ba4ebd6833ab075241140f5d08d0ab2604" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg>Fork <span id="repo-network-counter" data-pjax-replace="true" data-turbo-replace="true" title="23" data-view-component="true" class="Counter">23</span> </a> </li> <li> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Fandreipfeiffer%2Fcss-in-js" rel="nofollow" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"star button","repository_id":327643454,"auth_type":"LOG_IN","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="61bc9387164e654cfd30918073f6f1b3f7d01aeb8cd1db5bb2eb59966753f9a4" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> <span id="repo-stars-counter-star" aria-label="846 users starred this repository" data-singular-suffix="user starred this repository" data-plural-suffix="users starred this repository" data-turbo-replace="true" title="846" data-view-component="true" class="Counter js-social-count">846</span> </a></div> </li> </ul> </div> </div> <div id="responsive-meta-container" data-turbo-replace> <div class="d-block d-md-none mb-2 px-3 px-md-4 px-lg-5"> <p class="f4 mb-3 "> A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js </p> <div class="mb-3"> <a class="Link--secondary no-underline mr-3" href="/andreipfeiffer/css-in-js/stargazers"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star mr-1"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> <span class="text-bold">846</span> stars </a> <a class="Link--secondary no-underline mr-3" href="/andreipfeiffer/css-in-js/forks"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-1"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <span class="text-bold">23</span> forks </a> <a class="Link--secondary no-underline mr-3 d-inline-block" href="/andreipfeiffer/css-in-js/branches"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-branch mr-1"> <path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path> </svg> <span>Branches</span> </a> <a class="Link--secondary no-underline d-inline-block" href="/andreipfeiffer/css-in-js/tags"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-tag mr-1"> <path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path> </svg> <span>Tags</span> </a> <a class="Link--secondary no-underline d-inline-block" href="/andreipfeiffer/css-in-js/activity"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pulse mr-1"> <path d="M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z"></path> </svg> <span>Activity</span> </a> </div> <div class="d-flex flex-wrap gap-2"> <div class="flex-1"> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Fandreipfeiffer%2Fcss-in-js" rel="nofollow" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"star button","repository_id":327643454,"auth_type":"LOG_IN","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="61bc9387164e654cfd30918073f6f1b3f7d01aeb8cd1db5bb2eb59966753f9a4" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn btn-block"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> </a></div> </div> <div class="flex-1"> <a href="/login?return_to=%2Fandreipfeiffer%2Fcss-in-js" rel="nofollow" id="files-overview-watch-button" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"notification subscription menu watch","repository_id":null,"auth_type":"LOG_IN","originating_url":"https://github.com/andreipfeiffer/css-in-js","user_id":null}}" data-hydro-click-hmac="1fceca7577de1f3406456e4063137ea61a3ebf6addf9169bd6bfa05e5d26c8b8" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn btn-block"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-e6042ea3-13e1-459c-9924-ad273cc6e6b3" for="files-overview-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </div> <span> </span> </div> </div> </div> <nav data-pjax="#js-repo-pjax-container" aria-label="Repository" data-view-component="true" class="js-repo-nav js-sidenav-container-pjax js-responsive-underlinenav overflow-hidden UnderlineNav px-3 px-md-4 px-lg-5"> <ul data-view-component="true" class="UnderlineNav-body list-style-none"> <li data-view-component="true" class="d-inline-flex"> <a id="code-tab" href="/andreipfeiffer/css-in-js" data-tab-item="i0code-tab" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches repo_packages repo_deployments repo_attestations /andreipfeiffer/css-in-js" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g c" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Code","target":"UNDERLINE_NAV.TAB"}" aria-current="page" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item selected"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code UnderlineNav-octicon d-none d-sm-inline"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> <span data-content="Code">Code</span> <span id="code-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="issues-tab" href="/andreipfeiffer/css-in-js/issues" data-tab-item="i1issues-tab" data-selected-links="repo_issues repo_labels repo_milestones /andreipfeiffer/css-in-js/issues" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g i" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Issues","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> <span data-content="Issues">Issues</span> <span id="issues-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="4" data-view-component="true" class="Counter">4</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="pull-requests-tab" href="/andreipfeiffer/css-in-js/pulls" data-tab-item="i2pull-requests-tab" data-selected-links="repo_pulls checks /andreipfeiffer/css-in-js/pulls" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g p" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Pull requests","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> <span data-content="Pull requests">Pull requests</span> <span id="pull-requests-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="actions-tab" href="/andreipfeiffer/css-in-js/actions" data-tab-item="i3actions-tab" data-selected-links="repo_actions /andreipfeiffer/css-in-js/actions" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g a" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Actions","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> <span data-content="Actions">Actions</span> <span id="actions-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="projects-tab" href="/andreipfeiffer/css-in-js/projects" data-tab-item="i4projects-tab" data-selected-links="repo_projects new_repo_project repo_project /andreipfeiffer/css-in-js/projects" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g b" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Projects","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table UnderlineNav-octicon d-none d-sm-inline"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path> </svg> <span data-content="Projects">Projects</span> <span id="projects-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="security-tab" href="/andreipfeiffer/css-in-js/security" data-tab-item="i5security-tab" data-selected-links="security overview alerts policy token_scanning code_scanning /andreipfeiffer/css-in-js/security" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g s" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Security","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield UnderlineNav-octicon d-none d-sm-inline"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span data-content="Security">Security</span> <include-fragment src="/andreipfeiffer/css-in-js/security/overall-count" accept="text/fragment+html"></include-fragment> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="insights-tab" href="/andreipfeiffer/css-in-js/pulse" data-tab-item="i6insights-tab" data-selected-links="repo_graphs repo_contributors dependency_graph dependabot_updates pulse people community /andreipfeiffer/css-in-js/pulse" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Insights","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> <span data-content="Insights">Insights</span> <span id="insights-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> </ul> <div style="visibility:hidden;" data-view-component="true" class="UnderlineNav-actions js-responsive-underlinenav-overflow position-absolute pr-3 pr-md-4 pr-lg-5 right-0"> <action-menu data-select-variant="none" data-view-component="true"> <focus-group direction="vertical" mnemonics retain> <button id="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-button" popovertarget="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-overlay" aria-controls="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-list" aria-haspopup="true" aria-labelledby="tooltip-4baf538d-104f-48d3-868c-c2f2238679f2" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--medium UnderlineNav-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal Button-visual"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg> </button><tool-tip id="tooltip-4baf538d-104f-48d3-868c-c2f2238679f2" for="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-button" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Additional navigation options</tool-tip> <anchored-position data-target="action-menu.overlay" id="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-overlay" anchor="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-button" id="action-menu-798e846d-ecc3-442f-977d-71dea67c550a-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li hidden="hidden" data-menu-item="i0code-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-ba25253f-4b05-46ce-9304-64bb39cf1a4d" href="/andreipfeiffer/css-in-js" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Code </span> </a> </li> <li hidden="hidden" data-menu-item="i1issues-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-6f85c93b-ed95-4b75-a251-e60ce6c82816" href="/andreipfeiffer/css-in-js/issues" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Issues </span> </a> </li> <li hidden="hidden" data-menu-item="i2pull-requests-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-25c76906-d6b9-4cc2-b432-33478c9e2d79" href="/andreipfeiffer/css-in-js/pulls" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Pull requests </span> </a> </li> <li hidden="hidden" data-menu-item="i3actions-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-b415fcdd-f9c4-428b-b0e9-49bb3d7ce946" href="/andreipfeiffer/css-in-js/actions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Actions </span> </a> </li> <li hidden="hidden" data-menu-item="i4projects-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-03da102a-f7f5-4103-8fbe-8e00184cec8c" href="/andreipfeiffer/css-in-js/projects" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Projects </span> </a> </li> <li hidden="hidden" data-menu-item="i5security-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-70817b2c-5da0-49cd-93f6-e3ae6458c2dd" href="/andreipfeiffer/css-in-js/security" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Security </span> </a> </li> <li hidden="hidden" data-menu-item="i6insights-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-74db7c41-2116-4adc-8b44-66c31ea6eb8d" href="/andreipfeiffer/css-in-js/pulse" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Insights </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu></div> </nav> </div> <turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class=""> <div id="repo-content-pjax-container" class="repository-content " > <h1 class='sr-only'>andreipfeiffer/css-in-js</h1> <div class="clearfix container-xl px-md-4 px-lg-5 px-3"> <div> <div style="max-width: 100%" data-view-component="true" class="Layout Layout--flowRow-until-md react-repos-overview-margin Layout--sidebarPosition-end Layout--sidebarPosition-flowRow-end"> <div data-view-component="true" class="Layout-main"> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_dompurify_dist_purify_es_mjs-dd1d3ea6a436.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_tanstack_query-core_build_modern_queryObserver_js-node_modules_tanstack_-defd52-843b41414e0e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_aria-live_aria-live_ts-ui_packages_promise-with-resolvers-polyfill_promise-with-r-17c672-34345cb18aac.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_paths_index_ts-e019c54eb886.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ref-selector_RefSelector_tsx-7496afc3784d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_commit-attribution_index_ts-ui_packages_commit-checks-status_index_ts-ui_packages-7094d4-15017f02e61c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_code-view-shared_hooks_shortcuts_ts-ui_packages_code-view-shared_utilities_styles-0dc246-f8753c5db08d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_code-view-shared_hooks_use-canonical-object_ts-ui_packages_code-view-shared_hooks-a83ec0-5ee2b562b57f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/repos-overview-ca785c0ab4fa.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.e0c9f0687c56358ed85e.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repos-overview.0ee7cac3ab511a65d9f9.module.css" /> <react-partial partial-name="repos-overview" data-ssr="true" data-attempted-ssr="true" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"initialPayload":{"allShortcutsEnabled":false,"path":"/","repo":{"id":327643454,"defaultBranch":"main","name":"css-in-js","ownerLogin":"andreipfeiffer","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2021-01-07T14:59:00.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/2570562?v=4","public":true,"private":false,"isOrgOwned":false},"currentUser":null,"refInfo":{"name":"main","listCacheKey":"v0:1621928487.8624918","canEdit":false,"refType":"branch","currentOid":"73cc44204cfd52298efaff19514689f3261eb33b"},"tree":{"items":[{"name":".yarn/releases","path":".yarn/releases","contentType":"directory","hasSimplifiedPath":true},{"name":"components/demo","path":"components/demo","contentType":"directory","hasSimplifiedPath":true},{"name":"pages","path":"pages","contentType":"directory"},{"name":"public","path":"public","contentType":"directory"},{"name":"styles","path":"styles","contentType":"directory"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".yarnrc","path":".yarnrc","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"next-env.d.ts","path":"next-env.d.ts","contentType":"file"},{"name":"package.json","path":"package.json","contentType":"file"},{"name":"tsconfig.json","path":"tsconfig.json","contentType":"file"},{"name":"yarn.lock","path":"yarn.lock","contentType":"file"}],"templateDirectorySuggestionUrl":null,"readme":null,"totalCount":13,"showBranchInfobar":false},"fileTree":null,"fileTreeProcessingTime":null,"foldersToFetch":[],"treeExpanded":false,"symbolsExpanded":false,"isOverview":true,"overview":{"banners":{"shouldRecommendReadme":false,"isPersonalRepo":false,"showUseActionBanner":false,"actionSlug":null,"actionId":null,"showProtectBranchBanner":false,"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_repo","releasePath":"/andreipfeiffer/css-in-js/releases/new?marketplace=true","showPublishActionBanner":false},"interactionLimitBanner":null,"showInvitationBanner":false,"inviterName":null,"actionsMigrationBannerInfo":{"releaseTags":[],"showImmutableActionsMigrationBanner":false,"initialMigrationStatus":null}},"codeButton":{"contactPath":"/contact","isEnterprise":false,"local":{"protocolInfo":{"httpAvailable":true,"sshAvailable":null,"httpUrl":"https://github.com/andreipfeiffer/css-in-js.git","showCloneWarning":null,"sshUrl":null,"sshCertificatesRequired":null,"sshCertificatesAvailable":null,"ghCliUrl":"gh repo clone andreipfeiffer/css-in-js","defaultProtocol":"http","newSshKeyUrl":"/settings/ssh/new","setProtocolPath":"/users/set_protocol"},"platformInfo":{"cloneUrl":"https://desktop.github.com","showVisualStudioCloneButton":false,"visualStudioCloneUrl":"https://windows.github.com","showXcodeCloneButton":false,"xcodeCloneUrl":"xcode://clone?repo=https%3A%2F%2Fgithub.com%2Fandreipfeiffer%2Fcss-in-js","zipballUrl":"/andreipfeiffer/css-in-js/archive/refs/heads/main.zip"}},"newCodespacePath":"/codespaces/new?hide_repo_select=true\u0026repo=327643454"},"popovers":{"rename":null,"renamedParentRepo":null},"commitCount":"337","overviewFiles":[{"displayName":"README.md","repoName":"css-in-js","refName":"main","path":"README.md","preferredFileType":"readme","tabName":"README","richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eA thorough analysis of CSS-in-TS\u003c/h1\u003e\u003ca id=\"user-content-a-thorough-analysis-of-css-in-ts\" class=\"anchor\" aria-label=\"Permalink: A thorough analysis of CSS-in-TS\" href=\"#a-thorough-analysis-of-css-in-ts\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis document contains an in-depth analysis of all the current \u003cstrong\u003eCSS-in-JS\u003c/strong\u003e solutions, that support \u003cstrong\u003eServer Side Rendering\u003c/strong\u003e and \u003cstrong\u003eTypeScript\u003c/strong\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe baseline reference we'll use for comparison is a \u003cstrong\u003eCSS Modules\u003c/strong\u003e approach.\u003cbr\u003e\nWe're using \u003cstrong\u003eNext.js\u003c/strong\u003e as a SSR framework for building resources.\u003cbr\u003e\nLast important aspect is type-safety with full \u003cstrong\u003eTypeScript\u003c/strong\u003e support.\u003c/p\u003e\n\u003cbr\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e🗓 \u003cem\u003eLast update: \u003cstrong\u003eAug 2021\u003c/strong\u003e\u003c/em\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e🗞 To get a shorter overview, you can checkout the \u003cstrong\u003earticle on CSS Tricks\u003c/strong\u003e:\u003cbr\u003e\n\u003ca href=\"https://css-tricks.com/a-thorough-analysis-of-css-in-js/\" rel=\"nofollow\"\u003ehttps://css-tricks.com/a-thorough-analysis-of-css-in-js/\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e📽 If you prefer a video instead, you can checkout my \u003cstrong\u003etalk from ngPartyCZ\u003c/strong\u003e:\u003cbr\u003e\n\u003ca href=\"https://www.youtube.com/watch?v=c7uWGhrAx9A\" rel=\"nofollow\"\u003ehttps://www.youtube.com/watch?v=c7uWGhrAx9A\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e✋ Please checkout our \u003ca href=\"#goals\"\u003egoals\u003c/a\u003e \u0026amp; \u003ca href=\"#disclaimer\"\u003edisclaimer\u003c/a\u003e before jumping to conclusions.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTable of contents\u003c/h2\u003e\u003ca id=\"user-content-table-of-contents\" class=\"anchor\" aria-label=\"Permalink: Table of contents\" href=\"#table-of-contents\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#motivation\"\u003eMotivation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#goals\"\u003eGoals\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#disclaimer\"\u003eDisclaimer\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#overview\"\u003e\u003cstrong\u003eOverview\u003c/strong\u003e\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#legend\"\u003eLegend\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#overall-observations\"\u003eOverall observations\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eLibraries review\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#css-modules\"\u003e\u003cstrong\u003eCSS Modules\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#styled-jsx\"\u003e\u003cstrong\u003eStyled JSX\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#styled-components\"\u003e\u003cstrong\u003eStyled Components\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#emotion\"\u003e\u003cstrong\u003eEmotion\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#typestyle\"\u003e\u003cstrong\u003eTypeStyle\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#fela\"\u003e\u003cstrong\u003eFela\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#stitches\"\u003e\u003cstrong\u003eStitches\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#jss\"\u003e\u003cstrong\u003eJSS\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#goober\"\u003e\u003cstrong\u003eGoober\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#compiled\"\u003e\u003cstrong\u003eCompiled\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#linaria\"\u003e\u003cstrong\u003eLinaria\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#vanilla-extract\"\u003e\u003cstrong\u003evanilla-extract\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#libraries-not-included\"\u003eLibraries not included\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#running-the-examples\"\u003eRunning the examples\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#feedback-and-suggestions\"\u003eFeedback and Suggestions\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMotivation\u003c/h2\u003e\u003ca id=\"user-content-motivation\" class=\"anchor\" aria-label=\"Permalink: Motivation\" href=\"#motivation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe \u003cstrong\u003eCSS language\u003c/strong\u003e and \u003cstrong\u003eCSS Modules\u003c/strong\u003e have some limitations, especially if we want to have type-safe code. Some of these limitations have alterative solutions, others are just being \u003cem\u003eannoying\u003c/em\u003e or \u003cem\u003eless than ideal\u003c/em\u003e:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles cannot be co-located with components\u003c/strong\u003e\u003cbr\u003e\nThis can be frustrating when authoring many small components, but it's not a deal breaker. However, the experience of moving back-and-forth between the \u003ccode\u003ecomponent.js\u003c/code\u003e file and the \u003ccode\u003ecomponent.css\u003c/code\u003e file, searching for a given class name, and not being able to easily \u003cem\u003e\"go to style definition\"\u003c/em\u003e, is an important productivity drawback.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyling pseudos and media queries requires selector duplication\u003c/strong\u003e\u003cbr\u003e\nAnother frustrating fact is the need to duplicate our CSS classes when defining \u003cstrong\u003epseudo classes and elements\u003c/strong\u003e, or \u003cstrong\u003emedia queries\u003c/strong\u003e. We can overcome these limitations using a CSS preprocessor like \u003cstrong\u003eSASS, LESS or Stylus\u003c/strong\u003e, that supports the \u003ccode\u003e\u0026amp;\u003c/code\u003e parent selector, enabling \u003cstrong\u003econtextual styling\u003c/strong\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-css notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\".button {}\n\n/* duplicated selector declaration for pseudo classes/elements */\n.button:hover {}\n.button::after {}\n\n@media (min-width: 640px) {\n /* duplicated selector declaration inside media queries */\n .button {}\n}\"\u003e\u003cpre\u003e.\u003cspan class=\"pl-c1\"\u003ebutton\u003c/span\u003e {}\n\n\u003cspan class=\"pl-c\"\u003e/* duplicated selector declaration for pseudo classes/elements */\u003c/span\u003e\n.\u003cspan class=\"pl-c1\"\u003ebutton\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003ehover\u003c/span\u003e {}\n.\u003cspan class=\"pl-c1\"\u003ebutton\u003c/span\u003e::\u003cspan class=\"pl-c1\"\u003eafter\u003c/span\u003e {}\n\n\u003cspan class=\"pl-k\"\u003e@media\u003c/span\u003e (\u003cspan class=\"pl-c1\"\u003emin-width\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e640\u003cspan class=\"pl-smi\"\u003epx\u003c/span\u003e\u003c/span\u003e) {\n \u003cspan class=\"pl-c\"\u003e/* duplicated selector declaration inside media queries */\u003c/span\u003e\n .\u003cspan class=\"pl-c1\"\u003ebutton\u003c/span\u003e {}\n}\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles usage is disconnected from their definition\u003c/strong\u003e\u003cbr\u003e\nWe get no IntelliSense with CSS Modules, of what CSS classes are defined in the \u003ccode\u003ecomponent.css\u003c/code\u003e file, making \u003cstrong\u003ecopy-paste\u003c/strong\u003e a required tool, lowering the DX. It also makes \u003cstrong\u003erefactoring very cumbersome\u003c/strong\u003e, because of the lack of safety.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eUsing type-safe design tokens in CSS is non-trivial\u003c/strong\u003e\u003cbr\u003e\nAny \u003ca href=\"https://spectrum.adobe.com/page/design-tokens/\" rel=\"nofollow\"\u003edesign tokens\u003c/a\u003e defined in JS/TS (to benefit from type-safety) cannot be directly used in CSS.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere are at least 2 workarounds for this issue, neither of them being elegant:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eWe could inject them as \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties\" rel=\"nofollow\"\u003eCSS Custom Properties / Variables\u003c/a\u003e, but we still don't get any IntelliSense or type-safety when using them in \u003ccode\u003e.module.css\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eWe could use \u003cstrong\u003einline styles\u003c/strong\u003e, which is less performant, and it also introduces a different way to write styles (camelCase vs. kebab-case), while also splitting the styling in 2 different places: the component file and the \u003ccode\u003e.css\u003c/code\u003e file.\u003c/li\u003e\n\u003cli\u003eWe could use CSS (or SASS) as the source of truth for design tokens, by storing them as CSS Custom Properties and read them from JS using DOM queries, but we'd still need to manually update both the CSS and JS code when we perform any change, because we don't have type-safety when dealing with CSS;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGoals\u003c/h2\u003e\u003ca id=\"user-content-goals\" class=\"anchor\" aria-label=\"Permalink: Goals\" href=\"#goals\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThere are specific goals we're looking for with this analysis:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🥇 SSR support and easy integration with Next.js\u003c/li\u003e\n\u003cli\u003e🥇 full TypeScript support\u003c/li\u003e\n\u003cli\u003e🥇 great DX with code completion \u0026amp; syntax highlight\u003c/li\u003e\n\u003cli\u003e🥈 light-weight\u003c/li\u003e\n\u003cli\u003e🥈 comprehensive documentation\u003c/li\u003e\n\u003cli\u003e🥉 intuitive API and low learning curve\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003eGetting even more specific, we wanted to experience the usage of various CSS-in-JS solutions regarding:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003edefining \u003cstrong\u003eglobal styles\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eusing \u003cstrong\u003emedia queries\u003c/strong\u003e \u0026amp; \u003cstrong\u003epseudo classes\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003edynamic styles\u003c/strong\u003e based on component \u003ccode\u003eprops\u003c/code\u003e (aka. component variants), or from user input\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ebundle size\u003c/strong\u003e impact\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDisclaimer\u003c/h2\u003e\u003ca id=\"user-content-disclaimer\" class=\"anchor\" aria-label=\"Permalink: Disclaimer\" href=\"#disclaimer\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis analysis is intended to be \u003cstrong\u003eobjective\u003c/strong\u003e and \u003cstrong\u003eunopinionated\u003c/strong\u003e:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eI have not built my own CSS-in-JS library.\u003c/li\u003e\n\u003cli\u003eI don't work on any of the libraries reviewed here.\u003c/li\u003e\n\u003cli\u003eI have \u003cstrong\u003eno intention or motivation for \u003cem\u003epromoting\u003c/em\u003e or \u003cem\u003etrashing\u003c/em\u003e\u003c/strong\u003e either of them.\u003c/li\u003e\n\u003cli\u003eI have \u003cstrong\u003eno prior experience\u003c/strong\u003e with any CSS-in-JS solution, so I'm \u003cstrong\u003enot biased\u003c/strong\u003e towards any of them.\u003c/li\u003e\n\u003cli\u003eI have \u003cstrong\u003eequally used\u003c/strong\u003e all the solutions analyzed here, which also means I have \u003cstrong\u003eno extensive experience\u003c/strong\u003e with any of them. So, you can safely say \u003cem\u003eI'm a jack of all \u003cdel\u003etrades\u003c/del\u003e CSS-in-JS libraries, but master of none\u003c/em\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003e👎 \u003cstrong\u003eWhat you WON'T FIND here?\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ewhich solution is \u003cem\u003e\"the best\"\u003c/em\u003e, as I'll not add any grading, which would also be highly subjective;\u003c/li\u003e\n\u003cli\u003ewhich solution is \u003cem\u003e\"the fastest\"\u003c/em\u003e, as I'm not concearned about rendering performance metrics (you can checkout \u003ca href=\"https://necolas.github.io/react-native-web/benchmarks/\" rel=\"nofollow\"\u003eNecholas's benchmarks\u003c/a\u003e for this);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003e👍 \u003cstrong\u003eWhat you WILL FIND here?\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ean overview of (almost) all CSS-in-JS solutions available at this date (see \u003cem\u003elast update\u003c/em\u003e on top) that we've tried to integrate into a \u003cstrong\u003eNext.js v11 + TypeScript\u003c/strong\u003e empty project, with \u003cstrong\u003eminimal effort\u003c/strong\u003e;\u003c/li\u003e\n\u003cli\u003ea limited set of \u003cstrong\u003equantitative metrics\u003c/strong\u003e that allowed us to evaluate these solutions, which might help you as well;\u003c/li\u003e\n\u003cli\u003ean additional list of \u003cstrong\u003equalitative personal observations\u003c/strong\u003e, which might be either minor details or deal-breakers when choosing a particular solution.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThe libraries are not presented in any particular order. If you're interested in a brief \u003cstrong\u003ehistory of CSS-in-JS\u003c/strong\u003e, you should checkout the \u003ca href=\"https://www.youtube.com/watch?v=75kmPj_iUOA\" rel=\"nofollow\"\u003ePast, Present, and Future of CSS-in-JS\u003c/a\u003e insightful talk by Max Stoiber.\u003c/p\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverview\u003c/h2\u003e\u003ca id=\"user-content-overview\" class=\"anchor\" aria-label=\"Permalink: Overview\" href=\"#overview\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#1-co-location\"\u003e1. Co‑location\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#2-dx\"\u003e2. DX\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#3-tag-tagged-templates\"\u003e3. \u003ccode\u003etag` `\u003c/code\u003e\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#4--object-styles\"\u003e4. \u003ccode\u003e{ }\u003c/code\u003e\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#5-ts\"\u003e5. TS\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#6--ctx-contextual-styles\"\u003e6. \u003ccode\u003e\u0026amp;\u003c/code\u003e ctx\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#7-nesting\"\u003e7. Nesting\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#8-theming\"\u003e8. Theme\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#9-css-static-css-extraction\"\u003e9. \u003ccode\u003e.css\u003c/code\u003e\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#10-style-tag\"\u003e10. \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#11-atomic-css\"\u003e11. Atomic\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#12-classname\"\u003e12. \u003ccode\u003eclassName\u003c/code\u003e\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#13-styled-\"\u003e13. \u003ccode\u003e\u0026lt;Styled /\u0026gt;\u003c/code\u003e\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#14-css-prop\"\u003e14. \u003ccode\u003ecss\u003c/code\u003e prop\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"center\"\u003e\u003ca href=\"#15-framework-agnostic\"\u003e15. Agnostic\u003c/a\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003e\u003ca href=\"#16-page-size-delta\"\u003e16. Page size delta\u003c/a\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#css-modules\"\u003eCSS Modules\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e-\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#styled-jsx\"\u003eStyled JSX\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+2.8 kB / +12.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#styled-components\"\u003eStyled Components\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+13.4 kB / +39.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#emotion\"\u003eEmotion\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+6.5 kB / +20.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#typestyle\"\u003eTypeStyle\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+2.1 kB / +8.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#fela\"\u003eFela\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+11.9 kB / +43.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#stitches\"\u003eStitches\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+5.3 kB / +17.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#jss\"\u003eJSS\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+18.2 kB / +60.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#goober\"\u003eGoober\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+1.1 kB / +4.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#compiled\"\u003eCompiled\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+3.5 kB / +9.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#linaria\"\u003eLinaria\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+2.7 kB / +6.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003e\u003ca href=\"#vanilla-extract\"\u003evanilla-extract\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🟠\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e❌\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003ccode\u003e+0.0 kB / -2.0 kB\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLEGEND:\u003c/h3\u003e\u003ca id=\"user-content-legend\" class=\"anchor\" aria-label=\"Permalink: LEGEND:\" href=\"#legend\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ - full \u0026amp; out-of-the-box support\u003c/li\u003e\n\u003cli\u003e🟠 - partial or limited support, less than ideal, or requiring some additional manual work for full support\u003c/li\u003e\n\u003cli\u003e❌ - lack of support\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e1. Co-location\u003c/h4\u003e\u003ca id=\"user-content-1-co-location\" class=\"anchor\" aria-label=\"Permalink: 1. Co-location\" href=\"#1-co-location\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe ability to define styles within the same file as the component. Note that we can also extract the styles into a separate file and import them, in case we prefer it.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2. DX\u003c/h4\u003e\u003ca id=\"user-content-2-dx\" class=\"anchor\" aria-label=\"Permalink: 2. DX\" href=\"#2-dx\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eRefers to the \u003cstrong\u003eDeveloper eXperience\u003c/strong\u003e which includes 2 main aspects:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003esyntax highlighting\u003c/strong\u003e for styles definition;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ecode-completion/suggestions\u003c/strong\u003e for supported CSS Properties and available values (we're evaluating only the suggestion feature, not type-safety);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e3. \u003ccode\u003etag` `\u003c/code\u003e (Tagged Templates)\u003c/h4\u003e\u003ca id=\"user-content-3-tag-tagged-templates\" class=\"anchor\" aria-label=\"Permalink: 3. tag` ` (Tagged Templates)\" href=\"#3-tag-tagged-templates\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSupport for defining \u003cstrong\u003estyles as strings\u003c/strong\u003e, using ES Tagged Templates:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003euses \u003ccode\u003ekebab-case\u003c/code\u003e for property names, just like plain CSS syntax;\u003c/li\u003e\n\u003cli\u003eenables easier migration from plain CSS to CSS-in-JS, because we don't have to completely re-write the styles;\u003c/li\u003e\n\u003cli\u003erequires installing additional code editor plugin(s) for \u003ca href=\"#2-dx\"\u003esyntax highlight and code completion\u003c/a\u003e, otherwise our code would look like a plain \u003ccode\u003estring\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003erequires an additional step to parse the string and convert it to JS, which can be done either at built time (slower builds), or at runtime (slightly larger payload);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e4. \u003ccode\u003e{ }\u003c/code\u003e (Object Styles)\u003c/h4\u003e\u003ca id=\"user-content-4--object-styles\" class=\"anchor\" aria-label=\"Permalink: 4. { } (Object Styles)\" href=\"#4--object-styles\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSupport for defining \u003cstrong\u003estyles as objects\u003c/strong\u003e, using plain JavaScript objects:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003euses \u003ccode\u003ecamelCase\u003c/code\u003e for property names, like we would do in \u003ca href=\"https://reactnative.dev/docs/next/style\" rel=\"nofollow\"\u003eReact Native\u003c/a\u003e;\u003c/li\u003e\n\u003cli\u003emigrating existing CSS requires a complete rewrite (don't know how we could automate this);\u003c/li\u003e\n\u003cli\u003ewe don't need additional tooling for syntax highlighting, as we get it out-of-the-box, by writting JS objects;\u003c/li\u003e\n\u003cli\u003ewithout proper TS definitions shipped with the library, we won't get code completion (☝️ we're only interested in TS, not Flow);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e5. TS\u003c/h4\u003e\u003ca id=\"user-content-5-ts\" class=\"anchor\" aria-label=\"Permalink: 5. TS\" href=\"#5-ts\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTypeScript support, either built-in, or via \u003ccode\u003e@types\u003c/code\u003e package, which should include:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003etypings for the library API;\u003c/li\u003e\n\u003cli\u003eStyle Object typings (in case the library supports the object syntax);\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eProps\u003c/code\u003e generics, where applicable (get type-safe access to component props types when defining dynamic styles);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e6. \u003ccode\u003e\u0026amp;\u003c/code\u003e ctx (Contextual Styles)\u003c/h4\u003e\u003ca id=\"user-content-6--ctx-contextual-styles\" class=\"anchor\" aria-label=\"Permalink: 6. \u0026amp; ctx (Contextual Styles)\" href=\"#6--ctx-contextual-styles\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSupport for \u003cstrong\u003econtextual styles\u003c/strong\u003e allowing us to easily define \u003cstrong\u003epseudo classes \u0026amp; elements\u003c/strong\u003e and \u003cstrong\u003emedia queries\u003c/strong\u003e without the need to repeat the selector, as required in plain CSS:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ecan either support the SASS/LESS/Stylus \u003ccode\u003e\u0026amp;\u003c/code\u003e parent selector;\u003c/li\u003e\n\u003cli\u003eor provide any specific API or syntax to achieve the same result;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e7. Nesting\u003c/h4\u003e\u003ca id=\"user-content-7-nesting\" class=\"anchor\" aria-label=\"Permalink: 7. Nesting\" href=\"#7-nesting\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSupport for \u003cstrong\u003earbitrary nested selectors\u003c/strong\u003e:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethis feature allows for great flexibility, which might be useful, or required in some specific use-cases;\u003c/li\u003e\n\u003cli\u003eto keep in mind that it also introduces too many ways of defining styles, which might cause chaos if we want to enforce good-practices, scalability and maintainability;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e8. Theming\u003c/h4\u003e\u003ca id=\"user-content-8-theming\" class=\"anchor\" aria-label=\"Permalink: 8. Theming\" href=\"#8-theming\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eBuilt-in support for Theming or managing tokens for a design system.\u003cbr\u003e\nWe \u003cstrong\u003ehaven't tested out this feature\u003c/strong\u003e, so we're only taking notes which libraries express their support in their docs.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e9. \u003ccode\u003e.css\u003c/code\u003e (Static CSS extraction)\u003c/h4\u003e\u003ca id=\"user-content-9-css-static-css-extraction\" class=\"anchor\" aria-label=\"Permalink: 9. .css (Static CSS extraction)\" href=\"#9-css-static-css-extraction\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDefined styles are extracted as static \u003ccode\u003e.css\u003c/code\u003e files:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eit reduces the total bundle/page size, because we don't need additional runtime library, for injecting and evaluating the styles;\u003c/li\u003e\n\u003cli\u003ethis approach \u003ca href=\"#-performance-metrics\"\u003eaffects \u003cstrong\u003eFCP/FMP\u003c/strong\u003e\u003c/a\u003e metrics negatively when users have an empty cache, and positively when having full cache;\u003c/li\u003e\n\u003cli\u003edynamic styling could potentially increase the generated file, because all style combinations must be pre-generated at built time;\u003c/li\u003e\n\u003cli\u003emore suitable for less interactive solutions, where we serve a lot of different pages and we want to take advantage of cached styles (ie: e-commerce, blogs);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e10. \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag\u003c/h4\u003e\u003ca id=\"user-content-10-style-tag\" class=\"anchor\" aria-label=\"Permalink: 10. \u0026lt;style\u0026gt; tag\" href=\"#10-style-tag\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDefined styles are injected inside \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tags in the document's \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003emakes dynamic styling super easy;\u003c/li\u003e\n\u003cli\u003eincurs larger payload, because we're also shipping a runtime library to handle dynamic styles;\u003c/li\u003e\n\u003cli\u003ewhen using SSR, styles required for the initial render are shipped twice to the client: once during SSR, and again during \u003ca href=\"https://developers.google.com/web/updates/2019/02/rendering-on-the-web#rehydration-issues\" rel=\"nofollow\"\u003ehydration\u003c/a\u003e;\u003c/li\u003e\n\u003cli\u003emore suited for highly dynamic and interactive (single page) applications;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e11. Atomic CSS\u003c/h4\u003e\u003ca id=\"user-content-11-atomic-css\" class=\"anchor\" aria-label=\"Permalink: 11. Atomic CSS\" href=\"#11-atomic-css\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe ability to generate \u003cstrong\u003eatomic css classes\u003c/strong\u003e, thus increasing style reusability, and reducing duplication:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethis generates a separate CSS class for each CSS property;\u003c/li\u003e\n\u003cli\u003ewe'll get larger HTML files, because each element will contain a larger number of CSS classes applied;\u003c/li\u003e\n\u003cli\u003etheoretically \u003ca href=\"https://sebastienlorber.com/atomic-css-in-js\" rel=\"nofollow\"\u003eatomic CSS-in-JS\u003c/a\u003e reduces the scaling factor of our styles, \u003ca href=\"https://www.youtube.com/watch?v=9JZHodNR184\" rel=\"nofollow\"\u003eFacebook is doing it\u003c/a\u003e as well;\u003c/li\u003e\n\u003cli\u003eit's debatable if the CSS total size reduction, is greater than the HTML size increase (what is the final delta)\u003c/li\u003e\n\u003cli\u003etheoretically, if the class names are shorter than the CSS property definition, the delta is positive so we're shipping less bytes (also depends a lot on compression, so not easy to draw a definite conclusion);\u003c/li\u003e\n\u003cli\u003ehowever, we're basically moving part of bytes from CSS to HTML, which might be harder to cache if we have dynamic SSRed pages;\u003c/li\u003e\n\u003cli\u003ealso, depends a lot on what changes more frequently: the styles? or the markup?\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e12. \u003ccode\u003eclassName\u003c/code\u003e\u003c/h4\u003e\u003ca id=\"user-content-12-classname\" class=\"anchor\" aria-label=\"Permalink: 12. className\" href=\"#12-classname\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe library API returns a \u003ccode\u003estring\u003c/code\u003e which we have to add to our component or element;\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethis is similar how we would normally style React components, so it's easy to adopt because we don't have to learn a new way of dealing with styles;\u003c/li\u003e\n\u003cli\u003eto combine styles we have to use string concatenation;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e13. \u003ccode\u003e\u0026lt;Styled /\u0026gt;\u003c/code\u003e\u003c/h4\u003e\u003ca id=\"user-content-13-styled-\" class=\"anchor\" aria-label=\"Permalink: 13. \u0026lt;Styled /\u0026gt;\" href=\"#13-styled-\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe API creates a wrapper (or \u003ccode\u003eStyled\u003c/code\u003e) component which includes the generated \u003ccode\u003eclassName\u003c/code\u003e(s):\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethis technique was first introduced and popularized by \u003ca href=\"#styled-components\"\u003eStyled Components\u003c/a\u003e, hence the name;\u003c/li\u003e\n\u003cli\u003ewe'll have to learn a new way to define styles, because we're not applying styles to elements, instead we're creating new components that include the styled elements;\u003c/li\u003e\n\u003cli\u003ethis also introduces a bit of indiretion when figuring out what native elements gets rendered inside a larger component;\u003c/li\u003e\n\u003cli\u003ewe end up creating components like \u003ccode\u003eStyledButton\u003c/code\u003e or \u003ccode\u003eStyledList\u003c/code\u003e instead of constants like \u003ccode\u003ebutton_styles\u003c/code\u003e or \u003ccode\u003elist_styles\u003c/code\u003e, so regarding naming it's pretty much the same thing;\u003c/li\u003e\n\u003cli\u003esince the styles/class names are not re-used (we re-use the entire component), it makes sense to encapsulate the styles within the component and not think about 2 different aspects of the same entity;\u003c/li\u003e\n\u003cli\u003eit's not React specific, can also be used with \u003ca href=\"https://github.com/styled-components/vue-styled-components\"\u003eVue\u003c/a\u003e;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e14. \u003ccode\u003ecss\u003c/code\u003e prop\u003c/h4\u003e\u003ca id=\"user-content-14-css-prop\" class=\"anchor\" aria-label=\"Permalink: 14. css prop\" href=\"#14-css-prop\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAllows passing styles using a special \u003ccode\u003ecss\u003c/code\u003e prop, similar how we would define inline styles, but the library generates a unique CSS class name behind the scenes:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eit's a convenient and ergonomic API;\u003c/li\u003e\n\u003cli\u003ethis technique was popularized by \u003ca href=\"#emotion\"\u003eEmotion\u003c/a\u003e v10;\u003c/li\u003e\n\u003cli\u003eit's seems to be available only for React/JSX-based syntax\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e15. Framework agnostic\u003c/h4\u003e\u003ca id=\"user-content-15-framework-agnostic\" class=\"anchor\" aria-label=\"Permalink: 15. Framework agnostic\" href=\"#15-framework-agnostic\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAllows usage without, or with any framework. Some libraries are built specifically for React only.\u003cbr\u003e\n\u003cstrong\u003eNOTE\u003c/strong\u003e: some libraries like \u003cstrong\u003eStitches\u003c/strong\u003e or \u003cstrong\u003eEmotion\u003c/strong\u003e document only React usage, although they have a \u003cstrong\u003ecore\u003c/strong\u003e that's framework agnostic.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e16. Page size delta\u003c/h4\u003e\u003ca id=\"user-content-16-page-size-delta\" class=\"anchor\" aria-label=\"Permalink: 16. Page size delta\" href=\"#16-page-size-delta\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe total page size difference in kB (transferred gzipped \u0026amp; minified / uncompressed \u0026amp; minified) compared to \u003cstrong\u003eCSS Modules\u003c/strong\u003e, for the entire index page production build using Next.js:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ekeep in mind that this includes an almost \u003cstrong\u003eempty page\u003c/strong\u003e, with only a couple of components;\u003c/li\u003e\n\u003cli\u003ethis is great for evaluating the minimal overhead, but does NOT offer any insight on the scaling factor: logarithmic, linear, or exponential;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eNOTE: all builds were done with Next.js \u003ccode\u003e11.1.0\u003c/code\u003e and the values are taken from Chrome Devtools Network tab, \u003ca href=\"https://developers.google.com/web/tools/chrome-devtools/network/reference#uncompressed\" rel=\"nofollow\"\u003eTransferred over network vs Resource size\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"#overview\"\u003e⬆️ to overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverall observations\u003c/h3\u003e\u003ca id=\"user-content-overall-observations\" class=\"anchor\" aria-label=\"Permalink: Overall observations\" href=\"#overall-observations\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe following observations apply for all solutions (with minor pointed exceptions).\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ Code splitting\u003c/h4\u003e\u003ca id=\"user-content--code-splitting\" class=\"anchor\" aria-label=\"Permalink: ✅ Code splitting\" href=\"#-code-splitting\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eComponents used only in a specific route will only be bundled for that route. This is something that Next.js performs out-of-the-box.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ Global styles\u003c/h4\u003e\u003ca id=\"user-content--global-styles\" class=\"anchor\" aria-label=\"Permalink: ✅ Global styles\" href=\"#-global-styles\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll solutions offer a way to define global styles, some with a dedicated API.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eCompiled\u003c/strong\u003e is the only library that doesn't have a dedicated API for global styles at the moment, but it is \u003ca href=\"https://github.com/atlassian-labs/compiled/issues/62\" data-hovercard-type=\"issue\" data-hovercard-url=\"/atlassian-labs/compiled/issues/62/hovercard\"\u003eplanned\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ SSR\u003c/h4\u003e\u003ca id=\"user-content--ssr\" class=\"anchor\" aria-label=\"Permalink: ✅ SSR\" href=\"#-ssr\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll solutions offer Server-Side Rendering support and are easy to integrate with Next.js.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ Vendor prefixes\u003c/h4\u003e\u003ca id=\"user-content--vendor-prefixes\" class=\"anchor\" aria-label=\"Permalink: ✅ Vendor prefixes\" href=\"#-vendor-prefixes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll solutions automatically add vendor specific prefixes out-of-the-box.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003evanilla-extract\u003c/strong\u003e is the only library that requires \u003ca href=\"https://github.com/seek-oss/vanilla-extract/blob/master/docs/treat-migration-guide.md#autoprefixer-is-no-longer-included\"\u003emanual setup\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ Unique class names\u003c/h4\u003e\u003ca id=\"user-content--unique-class-names\" class=\"anchor\" aria-label=\"Permalink: ✅ Unique class names\" href=\"#-unique-class-names\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll solutions generate unique class names, like CSS Modules do. The algorithm used to generate these names varies a lot between libraries:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003esome libraries use a \u003cstrong\u003ehashing\u003c/strong\u003e algorithm, requiring more computing, but resulting in idempotent names (for example: \u003ccode\u003e.heading\u003c/code\u003e style from \u003ccode\u003eCard\u003c/code\u003e component will always have the \u003ccode\u003e.Card_heading_h7Ys5\u003c/code\u003e hash);\u003c/li\u003e\n\u003cli\u003eother libraries use \u003cstrong\u003ecounting\u003c/strong\u003e, basically incrementing either a number (\u003ccode\u003e.heading-0-2-1\u003c/code\u003e, \u003ccode\u003e.input-0-2-2\u003c/code\u003e), or the alphabet letters (\u003ccode\u003ea, b, c, ... aa, ab, ac\u003c/code\u003e, etc), making this approach more performant, but resulting in non-idempotent class names (can't figure out if this has any potential drawbacks or not);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ No inline styles\u003c/h4\u003e\u003ca id=\"user-content--no-inline-styles\" class=\"anchor\" aria-label=\"Permalink: ✅ No inline styles\" href=\"#-no-inline-styles\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNone of the solutions generate inline styles, which is an older approach, used by Radium \u0026amp; Glamor. The approach is \u003ca href=\"https://esbench.com/bench/5908f78199634800a0347e94\" rel=\"nofollow\"\u003eless performant than CSS classes\u003c/a\u003e, and it's \u003ca href=\"https://reactjs.org/docs/dom-elements.html#style\" rel=\"nofollow\"\u003enot recommended\u003c/a\u003e as a primary method for defining styles. It also implies using JS event handlers to trigger pseudo classes, as inline styles do not support them. Apparently, all modern solutions nowadays moved away from this approach.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ Full CSS support\u003c/h4\u003e\u003ca id=\"user-content--full-css-support\" class=\"anchor\" aria-label=\"Permalink: ✅ Full CSS support\" href=\"#-full-css-support\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll solutions support most CSS properties that you would need: \u003cstrong\u003epseudo classes \u0026amp; elements\u003c/strong\u003e, \u003cstrong\u003emedia queries\u003c/strong\u003e and \u003cstrong\u003ekeyframes\u003c/strong\u003e are the ones that we've tested.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e✅ Critical CSS extraction\u003c/h4\u003e\u003ca id=\"user-content--critical-css-extraction\" class=\"anchor\" aria-label=\"Permalink: ✅ Critical CSS extraction\" href=\"#-critical-css-extraction\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMost solutions market themselves as being able to \u003cem\u003e\u003cstrong\u003e\"extract critical CSS\"\u003c/strong\u003e\u003c/em\u003e during SSR. Please note that this does \u003cstrong\u003eNOT refer\u003c/strong\u003e to \u003ca href=\"https://web.dev/extract-critical-css/\" rel=\"nofollow\"\u003eabove-the-fold critical CSS extraction\u003c/a\u003e, as we initially thought.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWhat they actually do:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eduring SSR, they only generate styles for the \u003cstrong\u003evisible\u003c/strong\u003e elements of the static rendered page;\u003c/li\u003e\n\u003cli\u003ethey don't inject CSS for elements that are dynamically rendered, or lazy loaded;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eWith 100% static CSS, there would be actually no benefit. With dynamic pages that render very few elements on the server, and most components are rendered dynamically on the client, the benefit increases.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eEXCEPTION\u003c/strong\u003e: libraries that use \u003ca href=\"#9-css-static-css-extraction\"\u003estatic CSS extraction\u003c/a\u003e.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e🟠 Performance Metrics\u003c/h4\u003e\u003ca id=\"user-content--performance-metrics\" class=\"anchor\" aria-label=\"Permalink: 🟠 Performance Metrics\" href=\"#-performance-metrics\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUnderstanding how these features affect \u003ca href=\"https://web.dev/vitals/#core-web-vitals\" rel=\"nofollow\"\u003eCore Web Vitals\u003c/a\u003e and \u003ca href=\"https://web.dev/lighthouse-performance/#metrics\" rel=\"nofollow\"\u003ePerformance Metrics\u003c/a\u003e in general is an extremely important factor to consider, and the way styles are delivered to the client has probably the biggest impact, so let's analyse this in detail.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAlso, there are 2 different scenarios we need to consider:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e📭 \u003cstrong\u003eEmpty cache\u003c/strong\u003e: the user visits our page for the first time, or a returning user visits our page after the cache was invalidated (a new version was released);\u003c/li\u003e\n\u003cli\u003e📬 \u003cstrong\u003eFull cache\u003c/strong\u003e: a returning user visits our page, and has all static resources cached (\u003ccode\u003e.js\u003c/code\u003e, \u003ccode\u003e.css\u003c/code\u003e, media, etc);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e1. \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/h4\u003e\u003ca id=\"user-content-1-css-file-extraction\" class=\"anchor\" aria-label=\"Permalink: 1. .css file extraction\" href=\"#1-css-file-extraction\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSolutions that generate \u003ccode\u003e.css\u003c/code\u003e static files, which you normally would include as \u003ccode\u003e\u0026lt;link\u0026gt;\u003c/code\u003e tag(s) in the \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e of your page, are basically \u003ca href=\"https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css\" rel=\"nofollow\"\u003erendering-blocking resources\u003c/a\u003e. This highly affects \u003cstrong\u003eFCP\u003c/strong\u003e, \u003cstrong\u003eLCP\u003c/strong\u003e and any other metric that follows.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e📭 \u003cstrong\u003eEmpty cache\u003c/strong\u003e\u003cbr\u003e\nIf the user has an empty cache, the following needs to happen, \u003cstrong\u003enegatively\u003c/strong\u003e impacting \u003cstrong\u003eFCP\u003c/strong\u003e and \u003cstrong\u003eLCP\u003c/strong\u003e:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethe browser needs to make an additional request, which implies a full \u003cstrong\u003eRTT\u003c/strong\u003e (Round Trip Time) to our server;\u003c/li\u003e\n\u003cli\u003etransfer all CSS file content;\u003c/li\u003e\n\u003cli\u003eparse it and build the CSSOM;\u003c/li\u003e\n\u003cli\u003ethese will delay any rendering of the \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e, even if the entire HTML is already loaded, and it may even be eagerly parsed, and some resources already fetched in advance;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eIt's true that you can fetch in \u003cstrong\u003eparallel\u003c/strong\u003e other \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e resources (additional \u003ccode\u003e.css\u003c/code\u003e or \u003ccode\u003e.js\u003c/code\u003e files), but this is generally a bad practice;\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e📬 \u003cstrong\u003eFull cache\u003c/strong\u003e\u003cbr\u003e\nHowever, on subsequent visits, the entire \u003ccode\u003e.css\u003c/code\u003e resource would be cached, so \u003cstrong\u003eFCP\u003c/strong\u003e and \u003cstrong\u003eLCP\u003c/strong\u003e would be positively impacted.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003e💡 \u003cstrong\u003eKey points\u003c/strong\u003e\u003cbr\u003e\nThis solution appears to be better suited when:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ewe have many Server Side Rendered pages that our users visit, maybe even containing a common \u003ccode\u003e.css\u003c/code\u003e file that can be cached when visiting other pages;\u003c/li\u003e\n\u003cli\u003ewe don't update the styles frequently, so they can be cached for longer periods of time;\u003c/li\u003e\n\u003cli\u003ewe want to optimize for returning visitors, affecting first-time visits instead;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2. \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injected styles\u003c/h4\u003e\u003ca id=\"user-content-2-style-tag-injected-styles\" class=\"anchor\" aria-label=\"Permalink: 2. \u0026lt;style\u0026gt; tag injected styles\" href=\"#2-style-tag-injected-styles\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDuring \u003cstrong\u003eSSR\u003c/strong\u003e, styles will be added as \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag(s) in the \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e of the page. Keep in mind that these usually do NOT include all styles needed for the page, because most libraries perform \u003ca href=\"#-critical-css-extraction\"\u003eCritical CSS extraction\u003c/a\u003e, so these \u003ccode\u003estyles\u003c/code\u003e should be usually smaller than the entire \u003ccode\u003e.css\u003c/code\u003e static file discussed previously.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e📭 \u003cstrong\u003eEmpty cache\u003c/strong\u003e\u003cbr\u003e\nBecause we're shipping less CSS bytes, and they are inlined inside the \u003ccode\u003e.html\u003c/code\u003e file, this would result in faster \u003cstrong\u003eFCP\u003c/strong\u003e and \u003cstrong\u003eLCP\u003c/strong\u003e:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ewe don't need additional requests for \u003ccode\u003e.css\u003c/code\u003e files, so the browser is not blocked;\u003c/li\u003e\n\u003cli\u003eif we move all other \u003ccode\u003e.js\u003c/code\u003e files requests to the end of the document, \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e won't do any requests, so rendering will occur super fast;\u003c/li\u003e\n\u003cli\u003ehowever, eventually we would ship additional bytes, that were not needed with static \u003ccode\u003e.css\u003c/code\u003e extraction:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethe runtime library (between 1.6kB - 20kB);\u003c/li\u003e\n\u003cli\u003ethe styles required for the page, bundled in \u003ccode\u003e.js\u003c/code\u003e files along with the components, during \u003ca href=\"https://developers.google.com/web/updates/2019/02/rendering-on-the-web#rehydration-issues\" rel=\"nofollow\"\u003ehydration\u003c/a\u003e (this includes all the critical CSS already shipped inside the \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag + others);\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eall these files are required to be fetched, parsed and executed to get a \u003cstrong\u003efully interactive\u003c/strong\u003e page;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e📬 \u003cstrong\u003eFull cache\u003c/strong\u003e\u003cbr\u003e\nWhen the user's cache is full, the additional \u003ccode\u003e.js\u003c/code\u003e files won't require fetching, as they are already cached.\u003cbr\u003e\nHowever, if the page is \u003cstrong\u003eSSRed\u003c/strong\u003e, the inlined critical CSS rendered in the \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag of the document will be downloaded again, unless we deal with static HTML that can be cached as well, or we deal with HTML caching on our infrastructure.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBut, by default, we will ship extra bytes on every page HTTP request, regardless if it's cached or not.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003e💡 \u003cstrong\u003eKey points\u003c/strong\u003e\u003cbr\u003e\nThis solution appears to be better suited when:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ewe deal with SPA (Single Page Applications), where we have one (or few) SSR pages;\u003c/li\u003e\n\u003cli\u003ewe update the styles frequently, so even if they could be cached, it won't have a positive impact;\u003c/li\u003e\n\u003cli\u003ewe want to optimize for first-time visitors, affecting returning visitors instead;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e🟠 Dead code removal\u003c/h4\u003e\u003ca id=\"user-content--dead-code-removal\" class=\"anchor\" aria-label=\"Permalink: 🟠 Dead code removal\" href=\"#-dead-code-removal\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMost solutions say they \u003cem\u003eremove unused code/styles\u003c/em\u003e. This is only \u003cstrong\u003ehalf-true\u003c/strong\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eUnused code is indeed more difficult to accumulate, especially if you compare it to plain \u003ccode\u003e.css\u003c/code\u003e files as we used to write \u003cem\u003ea decade ago\u003c/em\u003e. But when compared to CSS Modules, the differencies are not that big. Any solution that offers the option to define \u003cstrong\u003earbitrary selectors\u003c/strong\u003e or \u003cstrong\u003enested styles\u003c/strong\u003e will bundle them, regardless if they are used or not inside our component. We've managed to ship unused SSR styles with all the tested solutions.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTrue \u0026amp; full unused code removal is difficult to implement, as the CSS syntax is not type-checked, nor statically analyzable. Also, the dynamic nature of components make it practically impossible in certain scenarios, especially when the markup is dynamically rendered:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003e\u0026amp; span\u003c/code\u003e: descendant elements;\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\u0026amp;:nth-child()\u003c/code\u003e: certain pseudo selectors;\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\u0026amp; .bg-${color}\u003c/code\u003e: dynamic selectors;\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e.parent \u0026amp;\u003c/code\u003e: parent selectors;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eBasically, what we get is code removal when we delete the component, or we don't import it anymore. That's implicit behaviour, because the styles are a direct dependency of the component. When the component is gone, so are its styles.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e🟠 Debugging / Inspecting\u003c/h4\u003e\u003ca id=\"user-content--debugging--inspecting\" class=\"anchor\" aria-label=\"Permalink: 🟠 Debugging / Inspecting\" href=\"#-debugging--inspecting\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThere are 2 methods to inject CSS into the DOM \u0026amp; update it from JavaScript:\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch5 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e1. Using \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag(s)\u003c/h5\u003e\u003ca id=\"user-content-1-using-style-tags\" class=\"anchor\" aria-label=\"Permalink: 1. Using \u0026lt;style\u0026gt; tag(s)\" href=\"#1-using-style-tags\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis approach implies adding one or more \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag(s) in the DOM (either in the \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e or somewhere in the \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e), using \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild\" rel=\"nofollow\"\u003e.appendChild()\u003c/a\u003e to add the \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e Node(s), in addition with either \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent\" rel=\"nofollow\"\u003e.textContent\u003c/a\u003e, \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML\" rel=\"nofollow\"\u003e.innerHTML\u003c/a\u003e to update the \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag(s).\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eusing this approach, we can easily \u003cem\u003esee\u003c/em\u003e what styles get added to the DOM, because we can inspect the DOM from our DevTools, like any other DOM Node;\u003c/li\u003e\n\u003cli\u003eusing only one \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag and updating its whole content, could be slow to update the entire DOM when we actually changed only a tiny set of CSS rule(s);\u003c/li\u003e\n\u003cli\u003emost libraries use this solution in \u003ccode\u003eDEVELOPMENT\u003c/code\u003e mode, because it provides a better debugging experience;\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eTypeStyle\u003c/strong\u003e uses this in \u003ccode\u003ePRODUCTION\u003c/code\u003e also;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch5 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2. Using \u003ccode\u003eCSSStyleSheet\u003c/code\u003e API\u003c/h5\u003e\u003ca id=\"user-content-2-using-cssstylesheet-api\" class=\"anchor\" aria-label=\"Permalink: 2. Using CSSStyleSheet API\" href=\"#2-using-cssstylesheet-api\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFirst used by \u003cstrong\u003eJSS\u003c/strong\u003e, this method uses \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule\" rel=\"nofollow\"\u003e\u003ccode\u003eCSSStyleSheet.insertRule()\u003c/code\u003e\u003c/a\u003e to inject CSS rules directly into the \u003cstrong\u003eCSSOM\u003c/strong\u003e.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eusing this approach it's a bit more difficult to \u003cem\u003esee\u003c/em\u003e what styles get injected into the CSSOM, because even if you see the CSS applied on the elements (thanks to \u003ca href=\"https://developer.chrome.com/blog/css-in-js/\" rel=\"nofollow\"\u003eCSS-in-JS support in Chrome\u003c/a\u003e) it will point to an empty \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag;\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eto see all the injected styles, you'll have to select the \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag;\u003c/li\u003e\n\u003cli\u003eget access to it via \u003ccode\u003e$0\u003c/code\u003e in Chrome DevTools (or get a reference to it in any other way, using the DOM API);\u003c/li\u003e\n\u003cli\u003eaccess \u003ccode\u003e.sheet.cssRules\u003c/code\u003e on the \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag to see the Array of CSS rules that it contains;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003ethis method is apparently more performant than the previous one, during dynamic styles update, so most libraries use this method in \u003ccode\u003ePRODUCTION\u003c/code\u003e;\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eperformance gains apply only when adding new CSS rules, or updating existing ones (ie: dynamic styles update at runtime);\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eJSS\u003c/strong\u003e and \u003cstrong\u003eStitches\u003c/strong\u003e use it in \u003ccode\u003eDEVELOPMENT\u003c/code\u003e mode as well;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e❌ No component deduping\u003c/h4\u003e\u003ca id=\"user-content--no-component-deduping\" class=\"anchor\" aria-label=\"Permalink: ❌ No component deduping\" href=\"#-no-component-deduping\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf the same component is imported by 2 different routes, it will be send twice to the client. This is surely a limitation of the bundler/build system, in our case Next.js, and \u003cstrong\u003enot related to the CSS-in-JS solution\u003c/strong\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIn Next.js, code-splitting works at the route level, bundling all components required for a specific route, but according to their \u003ca href=\"https://nextjs.org/blog/next-9-2#improved-code-splitting-strategy\" rel=\"nofollow\"\u003eofficial blog\u003c/a\u003e and \u003ca href=\"https://web.dev/granular-chunking-nextjs/\" rel=\"nofollow\"\u003eweb.dev\u003c/a\u003e if a component is used in \u003cstrong\u003emore than 50%\u003c/strong\u003e of the pages, it should be included in the \u003ccode\u003ecommons\u003c/code\u003e bundle. However, in our example, we have 2 pages, each of them importing the \u003ccode\u003eButton\u003c/code\u003e component, and it's included in each page bundle, not in the \u003ccode\u003ecommons\u003c/code\u003e bundle. Since the code required for styling is bundled with the component, this limitation will impact the styles as well, so it's worth keeping this in mind.\u003c/p\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCSS Modules\u003c/h3\u003e\u003ca id=\"user-content-css-modules\" class=\"anchor\" aria-label=\"Permalink: CSS Modules\" href=\"#css-modules\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis is a well established, mature and solid approach. Without a doubt, it's a great improvement over BEM, SMACCS, OOCSS, or any other scalable CSS methodology to structure and organize our CSS, especially in component-based applications.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eLaunched in \u003cstrong\u003e2015\u003c/strong\u003e | \u003ca href=\"#overview\"\u003eBack to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Styles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo TypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ plain CSS\u003c/li\u003e\n\u003cli\u003e❌ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ Contextual styles: \u003cem\u003e(requires SASS, LESS or Stylus)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003eThis is the baseline we'll consider when comparing all the following \u003cstrong\u003eCSS-in-JS\u003c/strong\u003e solutions. Checkout the \u003ca href=\"#motivation\"\u003emotivation\u003c/a\u003e to better understand the limitations of this approach that we're trying to fill.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e76.7 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e233 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.19 kB 68.7 kB\n├ └ css/1d1f8eb014b85b65feee.css 450 B\n├ /_app 0 B 66.5 kB\n├ ○ /404 194 B 66.7 kB\n└ ○ /other 744 B 67.2 kB\n └ css/1c8bc5a96764df6b92b4.css 481 B\n+ First Load JS shared by all 66.5 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.40892d.js 555 B\n ├ chunks/webpack.ddd010.js 822 B\n └ css/a92bf2d3acbab964f6ac.css 319 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.19 kB 68.7 kB\n├ └ css/1d1f8eb014b85b65feee.css 450 B\n├ /_app 0 B 66.5 kB\n├ ○ /404 194 B 66.7 kB\n└ ○ /other 744 B 67.2 kB\n └ css/1c8bc5a96764df6b92b4.css 481 B\n+ First Load JS shared by all 66.5 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.40892d.js 555 B\n ├ chunks/webpack.ddd010.js 822 B\n └ css/a92bf2d3acbab964f6ac.css 319 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStyled JSX\u003c/h3\u003e\u003ca id=\"user-content-styled-jsx\" class=\"anchor\" aria-label=\"Permalink: Styled JSX\" href=\"#styled-jsx\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eVery simple solution, doesn't have a dedicated website for documentation, everything is on Github. It's not popular, but it is the built-in solution in Next.js.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e4.0\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://github.com/vercel\"\u003eVercel\u003c/a\u003e | Launched in \u003cstrong\u003e2017\u003c/strong\u003e | \u003ca href=\"https://github.com/vercel/styled-jsx\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e: to get syntax highlighting \u0026amp; code completion, an editor extension is required\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eTypeScript support\u003c/strong\u003e: \u003ccode\u003e@types\u003c/code\u003e can be additionaly installed, but the API is too minimal to require TS\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNot Framework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Tagged Templates\u003c/li\u003e\n\u003cli\u003e❌ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😌 out-of-the-box support with Next.js\u003c/li\u003e\n\u003cli\u003e👍 for user input styles, it generates a new class name for each change, but it removes the old one\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😏 unlike CSS modules, we can target HTML \u003ccode\u003eelements\u003c/code\u003e also, and it generates unique class names for them (not sure if it's a good practice, though)\u003c/li\u003e\n\u003cli\u003e🤓 we'll need to optimize our styles by \u003ca href=\"https://github.com/vercel/styled-jsx#dynamic-styles\"\u003esplitting static \u0026amp; dynamic styles\u003c/a\u003e, to avoid rendering duplicated styles\u003c/li\u003e\n\u003cli\u003e🤨 unique class names are added to elements, even if we don't target them in our style definition, resulting in un-needed slight html pollution (optimizing this is cumbersome, and it's \u003cem\u003ea lot of work for little benefit\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003e😕 it will bundle any defined styles, regardless if they are used or not, just like plain CSS\u003c/li\u003e\n\u003cli\u003e😢 there's no support for \u003cstrong\u003econtextual styles\u003c/strong\u003e, so defining \u003cstrong\u003epseudo classes\u003c/strong\u003e or \u003cstrong\u003emedia queries\u003c/strong\u003e has the same downsides as plain CSS, requiring selectors/class names duplication (a \u003ca href=\"https://github.com/vercel/styled-jsx#css-preprocessing-via-plugins\"\u003eSASS plugin\u003c/a\u003e is required to get this feature)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOverall, we felt like writting plain CSS, with the added benefit of being able to define the styles along with the component, so we \u003cstrong\u003edon't need an additional \u003ccode\u003e.css\u003c/code\u003e file\u003c/strong\u003e. Indeed, this is the philosophy of the library: supporting CSS syntax inside the component file. We can \u003cstrong\u003euse any JS/TS constants of functions\u003c/strong\u003e with string interpolation. Working with \u003cstrong\u003edynamic styles is pretty easy\u003c/strong\u003e because it's plain JavaScript in the end. We get all these benefits at a very low price, with a pretty \u003cstrong\u003esmall bundle overhead\u003c/strong\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe downsides are the overall experience of writting plain CSS. \u003cstrong\u003eWithout nesting support\u003c/strong\u003e pseudo classes/elements and media queries getting pretty cumbersome to manage.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e79.5 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e245 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+2.8 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+12 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.65 kB 72.6 kB\n├ /_app 0 B 70 kB\n├ ○ /404 194 B 70.2 kB\n└ ○ /other 1.18 kB 71.2 kB\n+ First Load JS shared by all 70 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.a4b061.js 4.12 kB\n └ chunks/webpack.61f1b6.js 778 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.65 kB 72.6 kB\n├ /_app 0 B 70 kB\n├ ○ /404 194 B 70.2 kB\n└ ○ /other 1.18 kB 71.2 kB\n+ First Load JS shared by all 70 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.a4b061.js 4.12 kB\n └ chunks/webpack.61f1b6.js 778 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStyled Components\u003c/h3\u003e\u003ca id=\"user-content-styled-components\" class=\"anchor\" aria-label=\"Permalink: Styled Components\" href=\"#styled-components\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor sure one of the most popular and mature solutions, with good documentation. It uses Tagged Templates to defines styles by default, but can use objects as well. It also popularized the \u003ccode\u003estyled\u003c/code\u003e components approach, which creates a new component along with the defined styles.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e5.3\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://twitter.com/mxstbr\" rel=\"nofollow\"\u003eMax Stoiber\u003c/a\u003e \u0026amp; \u003ca href=\"https://opencollective.com/styled-components#category-ABOUT\" rel=\"nofollow\"\u003eothers\u003c/a\u003e | Launched in \u003cstrong\u003e2016\u003c/strong\u003e | \u003ca href=\"https://styled-components.com/docs\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e: \u003ccode\u003e@types\u003c/code\u003e must be additionaly installed, via DefinitelyTyped\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e: requires an editor extension/plugin\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-1\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-1\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🤓 we need to split static \u0026amp; dynamic styles, otherwise it will render duplicate output\u003c/li\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e😵 we can mix Tagged Templates with Styled Objects, which could lead to convoluted and different syntax for each approach (kebab vs camel, EOL character, quotes, interpolation, etc)\u003c/li\u003e\n\u003cli\u003e🥴 some more complex syntax appears to be a bit cumbersome to get right (mixing animations with Styled Objects, dynamic styles based on \u003ccode\u003eProps\u003c/code\u003e variations, etc)\u003c/li\u003e\n\u003cli\u003e🤫 for user input styles, it generates a new class name for each update, but it does NOT remove the old ones, appending indefinitely to the DOM\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-1\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-1\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eStyled components offers a novel approach to styling components using the \u003ccode\u003estyled\u003c/code\u003e method which creates a new component including the defined styles. We don't feel like writting CSS, so coming from CSS Modules we'll have to learn a new, more programatic way, to define styles. Because it allows both \u003ccode\u003estring\u003c/code\u003e and \u003ccode\u003eobject\u003c/code\u003e syntax, it's a pretty flexibile solution both for migrating our existing styles, and for starting a project from scratch. Also, the maintainers did a pretty good job keeping up with most of the innovations in this field.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eHowever before adopting it, we must be aware that it comes with a certain cost for our bundle size.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e90.1 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e272 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+13.4 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+39 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.52 kB 83.1 kB\n├ /_app 0 B 80.6 kB\n├ ○ /404 194 B 80.8 kB\n└ ○ /other 1.06 kB 81.7 kB\n+ First Load JS shared by all 80.6 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.731ace.js 14.7 kB\n └ chunks/webpack.ddd010.js 822 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.52 kB 83.1 kB\n├ /_app 0 B 80.6 kB\n├ ○ /404 194 B 80.8 kB\n└ ○ /other 1.06 kB 81.7 kB\n+ First Load JS shared by all 80.6 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.731ace.js 14.7 kB\n └ chunks/webpack.ddd010.js 822 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEmotion\u003c/h3\u003e\u003ca id=\"user-content-emotion\" class=\"anchor\" aria-label=\"Permalink: Emotion\" href=\"#emotion\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eProbably the most comprehensive, complete and sofisticated solution. Detailed documentation, fully built with TypeScript, looks very mature, rich in features and well maintained.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e11.4\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://twitter.com/mitchellhamiltn\" rel=\"nofollow\"\u003eMitchell Hamilton\u003c/a\u003e \u0026amp; \u003ca href=\"https://opencollective.com/emotion#category-ABOUT\" rel=\"nofollow\"\u003eothers\u003c/a\u003e | Launched in \u003cstrong\u003e2017\u003c/strong\u003e | \u003ca href=\"https://emotion.sh/docs/introduction\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e: for using the \u003ccode\u003estyled\u003c/code\u003e components approach, an additional editor plugin is required\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e \u003cem\u003e(using \u003ca href=\"https://emotion.sh/docs/@emotion/css\" rel=\"nofollow\"\u003e@emotion/css\u003c/a\u003e)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-1\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-1\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😎 the \u003ccode\u003ecss\u003c/code\u003e prop offers great ergonomics during development, however it seems to be a newer approach, based on \u003ca href=\"https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html\" rel=\"nofollow\"\u003eReact 17 new \u003ccode\u003ejsx\u003c/code\u003e transform\u003c/a\u003e, and \u003ca href=\"https://emotion.sh/docs/css-prop\" rel=\"nofollow\"\u003econfiguring\u003c/a\u003e it is not trivial, differs on your setup, and implies some boilerplate (which should change soon and become easier)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-2\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-2\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e🤫 for user input styles, it generates a new class name for each update, but it does NOT remove the old ones, appending indefinitely to the DOM\u003c/li\u003e\n\u003cli\u003e😑 using \u003ccode\u003estyled\u003c/code\u003e approach will add \u003ccode\u003e3 kB\u003c/code\u003e to our bundle, because it's imported from a separate package\u003c/li\u003e\n\u003cli\u003e🤔 don't know how to split static and dynamic styles, resulting in highly polluted duplicated styles for component variants, specifically problematic for SSR (same applies to \u003ccode\u003ecss\u003c/code\u003e prop \u0026amp; \u003ccode\u003estyled\u003c/code\u003e components)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-2\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-2\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOverall Emotion looks to be a very solid and flexible approach. The novel \u003ccode\u003ecss\u003c/code\u003e prop approach offers great ergonomics for developers. Working with dynamic styles and TypeScript is pretty easy and intuitive. Supporting both \u003ccode\u003estrings\u003c/code\u003e and \u003ccode\u003eobjects\u003c/code\u003e when defining styles, it can be easily used both when migrating from plain CSS, or starting from scratch. The bundle overhead is not negligible, but definitely much smaller than other solutions, especially if you consider the rich set of features that it offers.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIt seems it doesn't have a dedicated focus on performance, but more on Developer eXperience. It looks like a perfect \"well-rounded\" solution.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e83.2 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e253 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+6.5 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+20 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.5 kB 76.4 kB\n├ /_app 0 B 73.9 kB\n├ ○ /404 194 B 74.1 kB\n└ ○ /other 1.07 kB 74.9 kB\n+ First Load JS shared by all 73.9 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.6cb893.js 23.3 kB\n ├ chunks/pages/_app.b6d380.js 7.68 kB\n └ chunks/webpack.ddd010.js 822 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.5 kB 76.4 kB\n├ /_app 0 B 73.9 kB\n├ ○ /404 194 B 74.1 kB\n└ ○ /other 1.07 kB 74.9 kB\n+ First Load JS shared by all 73.9 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.6cb893.js 23.3 kB\n ├ chunks/pages/_app.b6d380.js 7.68 kB\n └ chunks/webpack.ddd010.js 822 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTypeStyle\u003c/h3\u003e\u003ca id=\"user-content-typestyle\" class=\"anchor\" aria-label=\"Permalink: TypeStyle\" href=\"#typestyle\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMinimal library, focused only on type-checking. It is framework agnostic, that's why it doesn't have a special API for handling dynamic styles. There are React wrappers available, but the typings feels a bit convoluted.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e2.1\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://twitter.com/basarat\" rel=\"nofollow\"\u003eBasarat\u003c/a\u003e | Launched in \u003cstrong\u003e2017\u003c/strong\u003e | \u003ca href=\"https://typestyle.github.io/\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e: uses TS \u003ccode\u003enamespaces\u003c/code\u003e to define theming, which is \u003ca href=\"https://basarat.gitbook.io/typescript/project/namespaces\" rel=\"nofollow\"\u003enot a recommended TS feature\u003c/a\u003e even by the author himself, or by TS core team member \u003ca href=\"https://youtu.be/8qm49TyMUPI?t=1277\" rel=\"nofollow\"\u003eOrta Therox\u003c/a\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-3\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-3\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e😕 it doesn't handle dynamic styles, so we have to use regular JS functions to compute styles\u003c/li\u003e\n\u003cli\u003e🤨 when composing styles, we'll have to manually add some internal typings\u003c/li\u003e\n\u003cli\u003e🤔 don't know how to split dynamic and static styles, so it's very easy to create duplicated generated code with dynamic styles, specifically problematic with SSR\u003c/li\u003e\n\u003cli\u003e😱 it creates a single \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag with all the styles, and replaces it on update, and apparently it doesn't use \u003ccode\u003einsertRule()\u003c/code\u003e, not even in production builds, which might be an important performance drawback in large \u0026amp; highly dynamic UIs\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-3\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-3\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOverall TypeStyle seems a minimal library, relatively easy to adopt because we don't have to rewrite our components, thanks to the classic \u003ccode\u003eclassName\u003c/code\u003e approach. However we do have to rewrite our styles, because of the Style Object syntax. We didn't feel like writting CSS, so there is a learning curve we need to climb.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWith Next.js or React in general we don't get much value out-of-the-box, so we still need to perform a lot of manual work. The external \u003ca href=\"https://github.com/Malpaux/react-typestyle\"\u003ereact-typestyle\u003c/a\u003e binding doesn't support hooks, it seems to be an abandoned project and the typings are too convoluted to be considered an elegant solution.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e78.8 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e241 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+2.1 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+8 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.44 kB 72.1 kB\n├ /_app 0 B 69.7 kB\n├ ○ /404 194 B 69.9 kB\n└ ○ /other 975 B 70.7 kB\n+ First Load JS shared by all 69.7 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.5b0422.js 3.81 kB\n └ chunks/webpack.61f1b6.js 778 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.44 kB 72.1 kB\n├ /_app 0 B 69.7 kB\n├ ○ /404 194 B 69.9 kB\n└ ○ /other 975 B 70.7 kB\n+ First Load JS shared by all 69.7 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.5b0422.js 3.81 kB\n └ chunks/webpack.61f1b6.js 778 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFela\u003c/h3\u003e\u003ca id=\"user-content-fela\" class=\"anchor\" aria-label=\"Permalink: Fela\" href=\"#fela\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt appears to be a mature solution, with quite a number of users. The API is intuitive and very easy to use, great integration for React using hooks.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e11.6\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://twitter.com/robinweser\" rel=\"nofollow\"\u003eRobin Weser\u003c/a\u003e | Launched in \u003cstrong\u003e2016\u003c/strong\u003e | \u003ca href=\"https://fela.js.org/docs/\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eAtomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eTypeScript support\u003c/strong\u003e: it exposes Flow types, which work ok, from our (limited) experience\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e: styles defined outside the component require \u003ca href=\"https://github.com/andreipfeiffer/css-in-js/blob/fela/components/input.tsx#L29\"\u003eexplicit typing\u003c/a\u003e to get code completion\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🟠 Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-2\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-2\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😌 easy and simple to use API, very intuitive\u003c/li\u003e\n\u003cli\u003e🥳 creates very short and atomic class names (like \u003ccode\u003ea\u003c/code\u003e, \u003ccode\u003eb\u003c/code\u003e, ...)\u003c/li\u003e\n\u003cli\u003e😎 it has a lot of plugins that can add many additional features (but will also increase bundle size)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-4\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-4\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e🤨 when defining styles outside the component, we have to explicitly add some internal typings to get code completion\u003c/li\u003e\n\u003cli\u003e🥺 there's no actual TS support and the maintainer considers it a \u003ca href=\"https://github.com/robinweser/fela/issues/590#issuecomment-409373362\" data-hovercard-type=\"issue\" data-hovercard-url=\"/robinweser/fela/issues/590/hovercard\"\u003elow priority\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e🤕 without TS support, we cannot get fully type-safe integration into Next.js + TS (there are \u003ca href=\"https://twitter.com/pfeiffer_andrei/status/1349106486740475904\" rel=\"nofollow\"\u003emissing types from the definition file\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e🤔 the docs say it supports string based styles, but they are a second-class citizen and they seem to work only for global styles\u003c/li\u003e\n\u003cli\u003e😵 some information in the docs is spread on various pages, sometimes hard to find without a search feature, and the examples and use cases are not comprehensive\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-4\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-4\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFela looks to be a mature solution, with active development. It introduces 2 great features which we enjoyed a lot. The first one is the basic principle that \u003cem\u003e\"Style as a Function of State\"\u003c/em\u003e which makes working with dynamic styles feel super natural and integrates perfectly with React's mindset. The second is atomic CSS class names, which should potentially scale great when used in large applications.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe lack of TS support however is a bummer, considering we're looking for a fully type-safe solution. Also, the scaling benefits of atomic CSS should be measured against the library bundle size.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e88.6 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e276 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+11.9 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+43 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.84 kB 81.7 kB\n├ /_app 0 B 78.9 kB\n├ ○ /404 194 B 79 kB\n└ ○ /other 1.43 kB 80.3 kB\n+ First Load JS shared by all 78.9 kB\n ├ chunks/framework.2191d1.js 42.4 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.32bc1d.js 12.6 kB\n └ chunks/webpack.ddd010.js 822 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.84 kB 81.7 kB\n├ /_app 0 B 78.9 kB\n├ ○ /404 194 B 79 kB\n└ ○ /other 1.43 kB 80.3 kB\n+ First Load JS shared by all 78.9 kB\n ├ chunks/framework.2191d1.js 42.4 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.32bc1d.js 12.6 kB\n └ chunks/webpack.ddd010.js 822 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStitches\u003c/h3\u003e\u003ca id=\"user-content-stitches\" class=\"anchor\" aria-label=\"Permalink: Stitches\" href=\"#stitches\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eVery young library, solid, modern and well-thought-out solution. The overall experience is just great, full TS support, a lot of other useful features baked in the lib.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e0.2.5 (beta)\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://github.com/modulz\"\u003eModulz\u003c/a\u003e | Launched in \u003cstrong\u003e2020\u003c/strong\u003e | \u003ca href=\"https://stitches.dev/docs\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e: \u003cem\u003e(available with \u003ccode\u003e@stitches/core\u003c/code\u003e)\u003c/em\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eAtomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e🟠 \u003ccode\u003ecss\u003c/code\u003e prop \u003cem\u003e(used only to override \u003ccode\u003estyled\u003c/code\u003e components)\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-3\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-3\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😌 easy and simple to use API, a pleasure to work with\u003c/li\u003e\n\u003cli\u003e😎 great design tokens management and usage\u003c/li\u003e\n\u003cli\u003e🥰 documentation is exactly what we'd expect: no more, no less\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-5\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-5\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e🤔 dynamic styles can be defined either using built-in \u003ccode\u003evariants\u003c/code\u003e (for predefined styles), or styles created inside the component to get access to the \u003ccode\u003eprops\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e🧐 would help a lot to get the search feature inside the docs\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-5\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-5\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eStitches is probably the most modern solution to this date, with full out-of-the-box support for TS. Without a doubt, they took some of the best features from other solutions and put them together for an awesome development experience. The first thing that impressed us was definitely the documentation. The second, is the API they expose which is close to top-notch. The features they provide are not huge in quantity, but are very well-thought-out.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eHowever, we cannot ignore the fact that it's still in beta. Also, the authors identify it as \u003cem\u003e\"near-zero runtime\"\u003c/em\u003e, but at \u003cstrong\u003e+9 kB gzipped\u003c/strong\u003e it's debatable.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e82.0 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e250 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+5.3 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+17 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.43 kB 75.2 kB\n├ /_app 0 B 72.8 kB\n├ ○ /404 194 B 73 kB\n└ ○ /other 984 B 73.8 kB\n+ First Load JS shared by all 72.8 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.ff82f0.js 6.93 kB\n └ chunks/webpack.61f1b6.js 778 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.43 kB 75.2 kB\n├ /_app 0 B 72.8 kB\n├ ○ /404 194 B 73 kB\n└ ○ /other 984 B 73.8 kB\n+ First Load JS shared by all 72.8 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.ff82f0.js 6.93 kB\n └ chunks/webpack.61f1b6.js 778 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eJSS\u003c/h3\u003e\u003ca id=\"user-content-jss\" class=\"anchor\" aria-label=\"Permalink: JSS\" href=\"#jss\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eProbably the grandaddy around here, JSS is a very mature solution being the first of them, and still being maintained. The API is intuitive and very easy to use, great integration for React using hooks.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e10.7\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://twitter.com/oleg008\" rel=\"nofollow\"\u003eOleg Isonen\u003c/a\u003e and \u003ca href=\"https://opencollective.com/jss#category-ABOUT\" rel=\"nofollow\"\u003eothers\u003c/a\u003e | Launched in \u003cstrong\u003e2014\u003c/strong\u003e | \u003ca href=\"https://cssinjs.org/\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🟠 Tagged Templates: \u003cem\u003e(available with additional \u003ca href=\"https://cssinjs.org/jss-plugin-template\" rel=\"nofollow\"\u003eplugin\u003c/a\u003e, with limited features)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e🟠 \u003ccode\u003estyled\u003c/code\u003e component \u003cem\u003e(available with additional \u003ca href=\"https://cssinjs.org/styled-jss\" rel=\"nofollow\"\u003eplugin\u003c/a\u003e)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-4\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-4\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😌 easy and simple to use API, very intuitive\u003c/li\u003e\n\u003cli\u003e😎 it has a lot of plugins that can add many additional features (but will also increase bundle size)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-6\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-6\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e😳 keep in mind that \u003ca href=\"https://github.com/cssinjs/jss/blob/master/packages/react-jss/package.json#L47\"\u003e\u003ccode\u003ereact-jss\u003c/code\u003e package\u003c/a\u003e, which is used with React/Next.js, depends on \u003ca href=\"https://cssinjs.org/jss-preset-default\" rel=\"nofollow\"\u003ejss-preset-default\u003c/a\u003e, which includes many \u003ca href=\"https://github.com/cssinjs/jss/blob/master/packages/jss-preset-default/package.json#L35-L47\"\u003eplugins\u003c/a\u003e by default, so you don't need to manually add some of the plugins;\u003c/li\u003e\n\u003cli\u003e🤔 \u003ccode\u003ereact-jss\u003c/code\u003e uses className by default. There's also \u003ccode\u003estyled-jss\u003c/code\u003e that uses \u003cstrong\u003eStyled Components\u003c/strong\u003e approach, but it has no types, and couldn't make it work on top of \u003ccode\u003ereact-jss\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003e😤 global styles were frustrating to setup, we've finally managed to used them thanks to \u003ca href=\"https://stackoverflow.com/questions/54201412/how-can-i-add-style-to-the-body-element-with-jss\" rel=\"nofollow\"\u003eStackOverFlow\u003c/a\u003e, because the docs have no mention of \u003ccode\u003einjectSheet\u003c/code\u003e API (or we couldn't find it anywhere);\u003c/li\u003e\n\u003cli\u003e😖 the docs are generally difficult to follow, and finding the information you need is a cumbersome process:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethere is no search;\u003c/li\u003e\n\u003cli\u003ethere are a lot of plugins, so you don't know where to look for a particular feature;\u003c/li\u003e\n\u003cli\u003esome plugins influence other plugins, or other docs pages, and they sometimes don't contain all the combinations of features, so the docs are not comprehensive (ie: we had to figure out on our own how to use \u003cstrong\u003econtextual styles\u003c/strong\u003e with \u003cstrong\u003emedia queries\u003c/strong\u003e).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-6\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-6\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe API is similar in many ways to React Native StyleSheets, while the hooks helper allows for easy dynamic styles definition. There are many plugins that can add a lot of features to the core functionality, but attention must be payed to the total bundle size, which is significant even with the bare minimum only.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAlso, being the first CSS-in-JS solution built, it lacks many of the modern features that focuses on developer experience.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e94.9 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e293 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+18.2 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+60 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.45 kB 88 kB\n├ /_app 0 B 85.6 kB\n├ ○ /404 194 B 85.8 kB\n└ ○ /other 992 B 86.6 kB\n+ First Load JS shared by all 85.6 kB\n ├ chunks/framework.2191d1.js 42.4 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.5f0007.js 19.2 kB\n └ chunks/webpack.9c89cc.js 956 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.45 kB 88 kB\n├ /_app 0 B 85.6 kB\n├ ○ /404 194 B 85.8 kB\n└ ○ /other 992 B 86.6 kB\n+ First Load JS shared by all 85.6 kB\n ├ chunks/framework.2191d1.js 42.4 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.5f0007.js 19.2 kB\n └ chunks/webpack.9c89cc.js 956 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGoober\u003c/h3\u003e\u003ca id=\"user-content-goober\" class=\"anchor\" aria-label=\"Permalink: Goober\" href=\"#goober\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA very light-weight solution, with a loads of features.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e2.0\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://twitter.com/cristianbote_\" rel=\"nofollow\"\u003eCristian Bote\u003c/a\u003e | Launched in \u003cstrong\u003e2019\u003c/strong\u003e | \u003ca href=\"https://goober.js.org/\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003estyled\u003c/code\u003e component (\u003cem\u003esee details below\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003e🟠 \u003ccode\u003ecss\u003c/code\u003e prop (\u003cem\u003eis supported, but requires a separate babel plugin\u003c/em\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-5\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-5\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🤏 really tiny\u003c/li\u003e\n\u003cli\u003e😎 it supports a very wide range of defining styles, so it's pretty versatile and full featured in this regard (however, I fear that having all these options, a large team could mix various ways of defining styles, so it's more difficult to \u003cem\u003eenforce consistency\u003c/em\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-7\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-7\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e🤫 for user input styles, it generates a new class name for each update, but it does NOT remove the old ones, appending indefinitely to the DOM\u003c/li\u003e\n\u003cli\u003e🤔 don't know how to split static and dynamic styles, resulting in highly polluted duplicated styles for component variants, specifically problematic for SSR\u003c/li\u003e\n\u003cli\u003e😱 it creates a single \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag with all the styles, and appends to it on update, and apparently it doesn't use \u003ccode\u003einsertRule()\u003c/code\u003e, not even in production builds, which might be an important performance drawback in large \u0026amp; highly dynamic UIs\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-7\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-7\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLooking at Goober you cannot ask yourself what kind of magic did Cristian Bote do to fit all the features inside this tiny library. It is really mind blowing. It is marketed as being \u003cem\u003e\"less than 1KB\"\u003c/em\u003e, which is not entirely accurate, but still... it's the smallest library we've tested.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e77.8 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e237 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+1.1 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+4 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.77 kB 71.1 kB\n├ /_app 0 B 68.3 kB\n├ ○ /404 194 B 68.5 kB\n└ ○ /other 2.39 kB 70.7 kB\n+ First Load JS shared by all 68.3 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.5ee014.js 2.42 kB\n └ chunks/webpack.61f1b6.js 778 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.77 kB 71.1 kB\n├ /_app 0 B 68.3 kB\n├ ○ /404 194 B 68.5 kB\n└ ○ /other 2.39 kB 70.7 kB\n+ First Load JS shared by all 68.3 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.5ee014.js 2.42 kB\n └ chunks/webpack.61f1b6.js 778 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCompiled\u003c/h3\u003e\u003ca id=\"user-content-compiled\" class=\"anchor\" aria-label=\"Permalink: Compiled\" href=\"#compiled\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA rather new library, having the huge Atlassian platform supporting and probably using it. Many existing features, even more in development, or planned for development.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e0.6\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://github.com/atlassian-labs\"\u003eAtlassian\u003c/a\u003e | Launched in \u003cstrong\u003e2020\u003c/strong\u003e | \u003ca href=\"https://compiledcssinjs.com/docs/\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eAtomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNot Framework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Built-in Theming support\u003c/strong\u003e \u003cem\u003e(at least at the moment, but it is \u003ca href=\"https://github.com/atlassian-labs/compiled/issues/18\" data-hovercard-type=\"issue\" data-hovercard-url=\"/atlassian-labs/compiled/issues/18/hovercard\"\u003eplanned\u003c/a\u003e)\u003c/em\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Arbitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🟠 \u003ccode\u003eclassName\u003c/code\u003e \u003cem\u003e(only supported with a custom \u003ca href=\"https://compiledcssinjs.com/docs/class-names\" rel=\"nofollow\"\u003eClassNames\u003c/a\u003e component)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ \u003ccode\u003e.css\u003c/code\u003e file extraction \u003cem\u003e(currently under development, will be shipped in 2021)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-6\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-6\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😌 using the \u003ccode\u003ecss\u003c/code\u003e prop is seamless and trivial, not requiring any special setup (unlike Emotion)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-8\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-8\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e🧐 styles are not placed in the \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e during SSR - instead they are placed right before the element using them in the \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e, which could potentially provide slightly faster Paint metrics, such as FCP, or LCP, because the browser can start rendering the body faster and incrementally, not waiting for the entire block of styles to be parsed\u003c/li\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e😔 currently has no API for global styles, but it is \u003ca href=\"https://github.com/atlassian-labs/compiled/issues/62\" data-hovercard-type=\"issue\" data-hovercard-url=\"/atlassian-labs/compiled/issues/62/hovercard\"\u003eplanned\u003c/a\u003e to be added\u003c/li\u003e\n\u003cli\u003e😳 \u003ccode\u003eClassNames\u003c/code\u003e API, which enables us to apply styles as class name strings, is a bit convoluted and weird at first sight.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-8\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-8\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCompiled is a very promising library. Considering that it offers both atomic CSS, and it plans to support static \u003ccode\u003e.css\u003c/code\u003e extraction, with excellent TypeScript support and style co-location, it would be quite unique (having only \u003ca href=\"#style9\"\u003estyle9\u003c/a\u003e as a direct competitor).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAlso, we cannot ignore that is has Atlassian supporting its development, which puts a (slightly) bigger weight on the confidence level.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe total bundle overhead is pretty small, the runtime library being quite light-weight. With static \u003ccode\u003e.css\u003c/code\u003e file extraction, this could potentially become even smaller.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e80.2 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e242 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+3.5 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+9 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.11 kB 71.8 kB\n├ /_app 0 B 66.5 kB\n├ ○ /404 194 B 66.7 kB\n└ ○ /other 888 B 70.6 kB\n+ First Load JS shared by all 66.5 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.ebe095.js 576 B\n ├ chunks/webpack.ddd010.js 822 B\n └ css/a92bf2d3acbab964f6ac.css 319 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.11 kB 71.8 kB\n├ /_app 0 B 66.5 kB\n├ ○ /404 194 B 66.7 kB\n└ ○ /other 888 B 70.6 kB\n+ First Load JS shared by all 66.5 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.ebe095.js 576 B\n ├ chunks/webpack.ddd010.js 822 B\n └ css/a92bf2d3acbab964f6ac.css 319 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLinaria\u003c/h3\u003e\u003ca id=\"user-content-linaria\" class=\"anchor\" aria-label=\"Permalink: Linaria\" href=\"#linaria\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLinaria is all about static CSS extraction and avoiding any runtime overhead.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e3.0 (beta)\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://github.com/callstack\"\u003eCallstack\u003c/a\u003e | Launched in \u003cstrong\u003e2018\u003c/strong\u003e | \u003ca href=\"https://github.com/callstack/linaria#documentation\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eStyles/Component co-location\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Atomic CSS\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Tagged Templates\u003c/li\u003e\n\u003cli\u003e❌ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e✅ Arbitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e✅ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-7\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-7\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😎 it's the only existing library at the moment (with a stable release) that supports both co-location \u0026amp; static CSS extraction (Compiled could also support this soon)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-9\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-9\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😕 bundles nested styles even if they are not used in component\u003c/li\u003e\n\u003cli\u003e😔 \u003ca href=\"https://github.com/callstack/linaria/blob/master/docs/BASICS.md#adding-global-styles\"\u003eglobal styling\u003c/a\u003e is documented, but we didn't get to make them work with Next.js\u003c/li\u003e\n\u003cli\u003e😳 documentation is not top-notch, there isn't a dedicated website, no search feature and it feels like trial \u0026amp; error when trying to find a piece of information\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-9\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-9\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLinaria is highly inspired from Astroturf, combining various features from other libraries.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion 3 is currently in Beta, not sure what the changelog is compared to v2. It's still in development by the \u003cem\u003eReact/Native geeks\u003c/em\u003e at \u003cstrong\u003eCallstack.io\u003c/strong\u003e, but we couldn't find which of the big players use it in production.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIt seems to have a slightly larger overall page size (\u003ccode\u003e2.9 KB\u003c/code\u003e), but we didn't investigate where does this come from. Also, there's an open question if this overhead is fixed or if it scales.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003ePS: thanks to \u003ca href=\"https://github.com/daniepetrov\"\u003eDaniil Petrov\u003c/a\u003e for his PR with the Next.js integration\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e79.4 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e239 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+2.7 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+6 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 4.99 kB 71.5 kB\n├ └ css/16f3e95ede28dcc048f2.css 423 B\n├ /_app 0 B 66.5 kB\n├ ○ /404 194 B 66.7 kB\n└ ○ /other 3.59 kB 70.1 kB\n └ css/3064299bff08067ec7dd.css 427 B\n+ First Load JS shared by all 66.5 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.98e8c3.js 598 B\n ├ chunks/webpack.ddd010.js 822 B\n └ css/7739287c04a618ea0c54.css 295 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 4.99 kB 71.5 kB\n├ └ css/16f3e95ede28dcc048f2.css 423 B\n├ /_app 0 B 66.5 kB\n├ ○ /404 194 B 66.7 kB\n└ ○ /other 3.59 kB 70.1 kB\n └ css/3064299bff08067ec7dd.css 427 B\n+ First Load JS shared by all 66.5 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.b2b078.js 23.1 kB\n ├ chunks/pages/_app.98e8c3.js 598 B\n ├ chunks/webpack.ddd010.js 822 B\n └ css/7739287c04a618ea0c54.css 295 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003evanilla-extract\u003c/h3\u003e\u003ca id=\"user-content-vanilla-extract\" class=\"anchor\" aria-label=\"Permalink: vanilla-extract\" href=\"#vanilla-extract\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eModern solution with great TypeScript integration and no runtime overhead. It's pretty minimal in its features, straightforward and opinionated. Everything is processed at compile time, and it generates static CSS files. Successor of \u003ca href=\"#treat\"\u003eTreat\u003c/a\u003e, also be called \"Treat v3\", is developed and maintained by the same authors.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eVersion: \u003cstrong\u003e\u003ccode\u003e1.2\u003c/code\u003e\u003c/strong\u003e | Maintained by \u003ca href=\"https://github.com/seek-oss/\"\u003eSeek OSS\u003c/a\u003e | Launched in \u003cstrong\u003e2021\u003c/strong\u003e | \u003ca href=\"https://vanilla-extract.style/\" rel=\"nofollow\"\u003eView Docs\u003c/a\u003e | ... \u003ca href=\"#overview\"\u003eback to Overview\u003c/a\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eTypeScript support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eBuilt-in Theming support\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eContext-aware code completion\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e✅ \u003cstrong\u003eFramework agnostic\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e🟠 \u003cstrong\u003eAtomic CSS\u003c/strong\u003e: can be achieved with \u003ca href=\"https://www.npmjs.com/package/@vanilla-extract/sprinkles\" rel=\"nofollow\"\u003eSprinkles\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e❌ \u003cstrong\u003eNo Styles/Component co-location\u003c/strong\u003e: styles must be placed in an external \u003ccode\u003e.css.ts\u003c/code\u003e file\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles definition method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e❌ Tagged Templates\u003c/li\u003e\n\u003cli\u003e✅ Style Objects\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles nesting\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ Contextual styles\u003c/li\u003e\n\u003cli\u003e❌ Abitrary nesting\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles apply method(s)\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003eclassName\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003estyled\u003c/code\u003e component\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003ecss\u003c/code\u003e prop\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eStyles output\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e✅ \u003ccode\u003e.css\u003c/code\u003e file extraction\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e tag injection\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOther benefits\u003c/h4\u003e\u003ca id=\"user-content-other-benefits-8\" class=\"anchor\" aria-label=\"Permalink: Other benefits\" href=\"#other-benefits-8\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e👮 forbids \u003cstrong\u003enested arbitrary selectors\u003c/strong\u003e (ie: \u003ccode\u003e\u0026amp; \u0026gt; span\u003c/code\u003e), which might be seen as a downside, but it actually discourages bad-practices like \u003cstrong\u003especificity wars\u003c/strong\u003e, which should be avoided when scaling CSS (however, this is impossible to be statically type-checked without \u003cem\u003epattern matching\u003c/em\u003e, so it will throw a runtime exception)\u003c/li\u003e\n\u003cli\u003e🥳 generates the same filename hash on build, if styles haven't changes, meaning that end-users benefit of CSS cache-ing even when deploying new versions with component updates only (logic, or content), without styles updates\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorth mentioning observations\u003c/h4\u003e\u003ca id=\"user-content-worth-mentioning-observations-10\" class=\"anchor\" aria-label=\"Permalink: Worth mentioning observations\" href=\"#worth-mentioning-observations-10\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e😌 in contrast with Treat, it relies on CSS Variables support, which means: 1) it doesn't work on IE, 2) is simpler and easier to maintain, 3) it supports other bundlers besides webpack\u003c/li\u003e\n\u003cli\u003e😕 bundles all styles, exported or not, even if they are not used in component\u003c/li\u003e\n\u003cli\u003e😥 it doesn't handle dynamic styles: you can use built-in \u003ccode\u003evariants\u003c/code\u003e based on predefined types, or \u003cstrong\u003einline styles\u003c/strong\u003e for user-defined styles\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConclusions\u003c/h4\u003e\u003ca id=\"user-content-conclusions-10\" class=\"anchor\" aria-label=\"Permalink: Conclusions\" href=\"#conclusions-10\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWe felt a lot like using CSS Modules: we need an external file for styles, we place the styles on the elements using \u003ccode\u003eclassName\u003c/code\u003e, we handle dynamic styles with \u003cstrong\u003einline styles\u003c/strong\u003e, etc. However, we don't write CSS, and the overall experience with TypeScript support is magnificent, because everything is typed, so we don't do any \u003cstrong\u003ecopy-paste\u003c/strong\u003e. Error messages are very helpful in guiding us when we do something we're not supposed to do.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003evanilla-extract is built with restrictions in mind, with a strong user-centric focus, balacing the developer experience with solid TypeScript support. It's also worth mentioning that \u003ca href=\"https://twitter.com/markdalgleish\" rel=\"nofollow\"\u003eMark Dalgleish\u003c/a\u003e, co-author of CSS Modules, works at Seek and he's also a contributor.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe authors vision is to think of vanilla-extract as a low-level utility for building higher-level frameworks, which will probably happen in the future.\u003c/p\u003e\n\u003cbr\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\"\u003e\u003c/th\u003e\n\u003cth align=\"right\"\u003eTransferred / gzipped\u003c/th\u003e\n\u003cth align=\"right\"\u003eUncompressed\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003eIndex page size\u003c/td\u003e\n\u003ctd align=\"right\"\u003e76.7 kB\u003c/td\u003e\n\u003ctd align=\"right\"\u003e231 kB\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"left\"\u003evs. CSS Modules\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e+0.0 kB\u003c/strong\u003e\u003c/td\u003e\n\u003ctd align=\"right\"\u003e\u003cstrong\u003e-2 kB\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cbr\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Page Size First Load JS\n┌ ○ / 2.09 kB 68.5 kB\n├ └ css/37c023369f5e1762e423.css 370 B\n├ /_app 0 B 66.4 kB\n├ ○ /404 194 B 66.6 kB\n└ ○ /other 611 B 67 kB\n └ css/a56b9d05c6da35ff125f.css 386 B\n+ First Load JS shared by all 66.4 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.700159.js 23.1 kB\n ├ chunks/pages/_app.bfd136.js 565 B\n ├ chunks/webpack.61f1b6.js 778 B\n └ css/23b89d9ef0ca05e4b917.css 286 B\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ePage Size First Load JS\n┌ ○ / 2.09 kB 68.5 kB\n├ └ css/37c023369f5e1762e423.css 370 B\n├ /_app 0 B 66.4 kB\n├ ○ /404 194 B 66.6 kB\n└ ○ /other 611 B 67 kB\n └ css/a56b9d05c6da35ff125f.css 386 B\n+ First Load JS shared by all 66.4 kB\n ├ chunks/framework.895f06.js 42 kB\n ├ chunks/main.700159.js 23.1 kB\n ├ chunks/pages/_app.bfd136.js 565 B\n ├ chunks/webpack.61f1b6.js 778 B\n └ css/23b89d9ef0ca05e4b917.css 286 B\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLibraries not included\u003c/h2\u003e\u003ca id=\"user-content-libraries-not-included\" class=\"anchor\" aria-label=\"Permalink: Libraries not included\" href=\"#libraries-not-included\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWe know there are a lot of other libraries out there, besides the ones covered above. We're only covered the ones that have support for \u003cstrong\u003eReact\u003c/strong\u003e, support for \u003cstrong\u003eSSR\u003c/strong\u003e, an easy integration with \u003cstrong\u003eNext.js\u003c/strong\u003e, good \u003cstrong\u003edocumentation\u003c/strong\u003e and a sense of ongoing \u003cstrong\u003esupport and maintenance\u003c/strong\u003e. Please checkout our \u003ca href=\"#goals\"\u003egoals\u003c/a\u003e.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTreat\u003c/h3\u003e\u003ca id=\"user-content-treat\" class=\"anchor\" aria-label=\"Permalink: Treat\" href=\"#treat\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://seek-oss.github.io/treat/\" rel=\"nofollow\"\u003eTreat\u003c/a\u003e was initially included in the analysis with v1.6, but removed for a few reasons:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003ethe library itself is replaced by \u003ca href=\"#vanilla-extract\"\u003evanilla-extract\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eNext.js integration is not supported with v2\u003c/li\u003e\n\u003cli\u003ewe couldn't upgrade to Next.js v11/webpack 5 even with v1\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eThe main difference between vanilla-extract and Treat is that the latter supports IE and legacy browsers as well.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003estyle9\u003c/h3\u003e\u003ca id=\"user-content-style9\" class=\"anchor\" aria-label=\"Permalink: style9\" href=\"#style9\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/johanholmerin/style9\"\u003eStyle9\u003c/a\u003e is a new library, inspired by Facebook's own CSS-in-JS solution called stylex. Style9 is unique because it's the only open source library that supports both \u003ccode\u003e.css\u003c/code\u003e static extraction + atomic CSS, and/or styles co-location. It has TS support and easy to integrate with Next.js.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eHowever, it has quite a few limitations (at least as of Feb 2021) that makes it practically unusable in a real production application that we would want to scale, both in code \u0026amp; team size:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ecannot use design tokens defined as \u003ccode\u003eEnum\u003c/code\u003e or \u003ccode\u003ePOJO\u003c/code\u003e, only constant primitives are supported, which is a \u003cstrong\u003ebig deal breaker\u003c/strong\u003e;\u003c/li\u003e\n\u003cli\u003edynamic styles are not trivial:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eit supports styles toggling, similar to \u003ccode\u003eclassNames\u003c/code\u003e lib, but not dynamically/computed/expression based;\u003c/li\u003e\n\u003cli\u003efor user styles, so we have to use inline styles;\u003c/li\u003e\n\u003cli\u003ethere is an experimental addon \u003ca href=\"https://github.com/johanholmerin/style9-components.macro\"\u003estyle9-components\u003c/a\u003e that tries to solve this;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eno global styles support;\u003c/li\u003e\n\u003cli\u003eno theming support (not a deal breaker for us):\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ethere is some exploration in this regard, with \u003ca href=\"https://github.com/johanholmerin/style9-theme.macro\"\u003estyle9-theme\u003c/a\u003e;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003edocumentation is not comprehensive, it contains a lot of code comments, without code examples, making it even more difficult to follow \u0026amp; understand\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eSome upsides:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eit's the first lib we've tested that actually doesn't bundle unused styles;\u003c/li\u003e\n\u003cli\u003eit doesn't allow arbitrary seletors / nesting, which is a good thing, because it enforces good practices and consistency;\u003c/li\u003e\n\u003cli\u003eit is framework agnostic;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eAs a conclusion, it wants to be a powerful solution with very interesting and unique set of features, but it's not mature yet. As far as we see, it's currently mostly designed towards more static solutions. Dynamic styling seems to be difficult to handle, at least for the moment.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTailwind\u003c/h3\u003e\u003ca id=\"user-content-tailwind\" class=\"anchor\" aria-label=\"Permalink: Tailwind\" href=\"#tailwind\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNot an actual CSS-in-JS library, more like a replacement for traditional CSS styling. It uses atomic CSS classes (some of them having multiple properties) that we attach to html elements. We don't write CSS, instead we use a different DSL to specify styles, pseudo classes, media queries, etc.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe reason we didn't include it in our thorough review is because it doesn't fully meet our \u003ca href=\"#goals\"\u003egoals\u003c/a\u003e:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eit doesn't provide TS support, or type-safety\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ewe cannot use out own design tokens from \u003ccode\u003e.ts\u003c/code\u003e files to include them in \u003ccode\u003etailwind.config\u003c/code\u003e (cannot \u003ccode\u003eimport\u003c/code\u003e any file, cannot require \u003ccode\u003e.ts\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eusing \u003ccode\u003etailwind.config\u003c/code\u003e directly offers no type-safety when importing it, or using \u003ca href=\"https://tailwindcss.com/docs/configuration#referencing-in-java-script\" rel=\"nofollow\"\u003e\u003ccode\u003eresolveConfig\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003ethere is a \u003ca href=\"https://github.com/DefinitelyTyped/DefinitelyTyped/pull/50921\" data-hovercard-type=\"pull_request\" data-hovercard-url=\"/DefinitelyTyped/DefinitelyTyped/pull/50921/hovercard\"\u003ePR on Definitely Typed\u003c/a\u003e, but we're not sure if it will support the custom config, as well\u003c/li\u003e\n\u003cli\u003ethere might be workarounds, but these are just proofs that there isn't a clean way to achieve this\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003edynamic styles have some limitations: we have to be aware of \u003ca href=\"https://tailwindcss.com/docs/optimizing-for-production#writing-purgeable-html\" rel=\"nofollow\"\u003epurging\u003c/a\u003e to not get missing design tokens in production builds\u003c/li\u003e\n\u003cli\u003ewe have to learn a new DSL: some style are similar and easy to deduce from their CSS counterparts, others are pretty different, and we have to learn (\u003ccode\u003erounded\u003c/code\u003e, \u003ccode\u003eplace-self/content\u003c/code\u003e, \u003ccode\u003edivide\u003c/code\u003e, \u003ccode\u003ering\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003esome advanced CSS features, like \u003ca href=\"https://github.com/tailwindlabs/tailwindcss/discussions/2119\" data-hovercard-type=\"discussion\" data-hovercard-url=\"/tailwindlabs/tailwindcss/discussions/2119/hovercard\"\u003e\u003ccode\u003e::after\u003c/code\u003e pseudo elements\u003c/a\u003e are tricky\u003c/li\u003e\n\u003cli\u003ethere are libraries like \u003ca href=\"https://github.com/Arthie/xwind\"\u003exwind\u003c/a\u003e which integrates Tailwind with CSS-in-JS solutions, which is supports our theory that Tawilwind is not a replacement for CSS-in-JS, not does it address the same problems\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eSome upsides:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003ewe don't write CSS, which is indeed difficult to master\u003c/li\u003e\n\u003cli\u003ethe entire team uses the same \"styling system\"\u003c/li\u003e\n\u003cli\u003ea shitton of predefined design tokens, plus the ability to customize them\u003c/li\u003e\n\u003cli\u003esuccessfully bundles only used styles, doesn't bundle all classes defined in \u003ccode\u003etailwind.config\u003c/code\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eexception: keyframe animations (spin, ping, etc)\u003c/li\u003e\n\u003cli\u003ebeware of purging\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eTailwind seems to be more than a \u003cem\u003estyling tool\u003c/em\u003e, it also offers some out-of-the-box utils + a ready-made design system that you can use right away.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAphrodite\u003c/h3\u003e\u003ca id=\"user-content-aphrodite\" class=\"anchor\" aria-label=\"Permalink: Aphrodite\" href=\"#aphrodite\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt's not a popular solution, the approach is similar to \u003cstrong\u003eReact Native StyleSheets\u003c/strong\u003e way of styling components. Has built-in TypeScript support and a simple API.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eglobal styles are a bit cumbersome to define\u003c/li\u003e\n\u003cli\u003eable to nest media queries \u0026amp; pseudo selectors, but cannot nest arbitrary rules/selectors\u003c/li\u003e\n\u003cli\u003eno dynamic out-of-the-box support, so we have to get around that, like inline styles I guess, or like in React Native\u003c/li\u003e\n\u003cli\u003edoesn't add any real value, except the ergonomics to colocate styles with the component.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGlamor\u003c/h3\u003e\u003ca id=\"user-content-glamor\" class=\"anchor\" aria-label=\"Permalink: Glamor\" href=\"#glamor\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eI got it started with Next.js, but it feels fragile. The \u003ca href=\"https://github.com/vercel/next.js/tree/canary/examples/with-glamor\"\u003eGlamor official example\u003c/a\u003e throws an error regarding \u003ccode\u003erehydrate\u003c/code\u003e. When commenting it out, it works, but not sure what the consequences are.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eit looks like an unmaintained or abandoned package\u003c/li\u003e\n\u003cli\u003edocumentation is pretty minimal\u003c/li\u003e\n\u003cli\u003elacks any TS support\u003c/li\u003e\n\u003cli\u003ehas a lot of documented experimental features, marked as \"buggy\"\u003c/li\u003e\n\u003cli\u003eit feels like a side/internal project at FB, that is not used anymore.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCxs\u003c/h3\u003e\u003ca id=\"user-content-cxs\" class=\"anchor\" aria-label=\"Permalink: Cxs\" href=\"#cxs\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDidn't manage to start it with Next.js + TypeScript. The \u003ca href=\"https://github.com/vercel/next.js/tree/canary/examples/with-cxs\"\u003eofficial example\u003c/a\u003e uses version 3, while today we have version 6. The example doesn't work, because the API has changed.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe solution looked interesting, because it is supposed to be very light-weight.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAstroturf\u003c/h3\u003e\u003ca id=\"user-content-astroturf\" class=\"anchor\" aria-label=\"Permalink: Astroturf\" href=\"#astroturf\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDidn't manage to start it with Next.js + TypeScript. There was an \u003ca href=\"https://github.com/vercel/next.js/tree/canary/examples/with-astroturf\"\u003eofficial example\u003c/a\u003e that used an older version of Next.js, but the example if not there anymore.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe solution is not that popular, but it was the first to use \u003ccode\u003e.css\u003c/code\u003e extraction with collocated styles.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOtion\u003c/h3\u003e\u003ca id=\"user-content-otion\" class=\"anchor\" aria-label=\"Permalink: Otion\" href=\"#otion\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLooks promising, atomic css and light-weight. It has a working \u003ca href=\"https://github.com/kripod/otion/tree/main/packages/example-nextjs\"\u003eNext.js example\u003c/a\u003e, but we didn't consider it because it lacks any documentation.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStyletron\u003c/h3\u003e\u003ca id=\"user-content-styletron\" class=\"anchor\" aria-label=\"Permalink: Styletron\" href=\"#styletron\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt looks like a not so popular solution, which also lacks support for TypeScript. It looks like the maintainers work at Uber and they use it internally. It focused on generating unique atomic CSS classes, which could potentially deduplicate a lot of code.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRadium\u003c/h3\u003e\u003ca id=\"user-content-radium\" class=\"anchor\" aria-label=\"Permalink: Radium\" href=\"#radium\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe project was put in \u003ca href=\"https://formidable.com/blog/2019/radium-maintenance/\" rel=\"nofollow\"\u003eMaintenance Mode\u003c/a\u003e. They recommend other solutions.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGlamorous\u003c/h3\u003e\u003ca id=\"user-content-glamorous\" class=\"anchor\" aria-label=\"Permalink: Glamorous\" href=\"#glamorous\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe project was \u003ca href=\"https://github.com/paypal/glamorous/issues/419\" data-hovercard-type=\"issue\" data-hovercard-url=\"/paypal/glamorous/issues/419/hovercard\"\u003ediscontinued\u003c/a\u003e in favor of Emotion.\u003c/p\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRunning the examples\u003c/h2\u003e\u003ca id=\"user-content-running-the-examples\" class=\"anchor\" aria-label=\"Permalink: Running the examples\" href=\"#running-the-examples\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEach implementation sits on their own branch, so we can have a clear separation at built time.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"# install dependencies\nyarn\n\n# for development\nyarn dev\n\n# for production\nyarn build\nyarn start\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e install dependencies\u003c/span\u003e\nyarn\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e for development\u003c/span\u003e\nyarn dev\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e for production\u003c/span\u003e\nyarn build\nyarn start\u003c/pre\u003e\u003c/div\u003e\n\u003cbr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFeedback and Suggestions\u003c/h2\u003e\u003ca id=\"user-content-feedback-and-suggestions\" class=\"anchor\" aria-label=\"Permalink: Feedback and Suggestions\" href=\"#feedback-and-suggestions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo get in touch, my DMs are open \u003ca href=\"https://twitter.com/pfeiffer_andrei\" rel=\"nofollow\"\u003e@pfeiffer_andrei\u003c/a\u003e.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSpecial thanks and appreciations\u003c/strong\u003e go to everyone that helped putting this document together, and making it more accurate:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eMartin Hochel (\u003ca href=\"https://twitter.com/martin_hotell\" rel=\"nofollow\"\u003e@martin_hotell\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003eOleg Isonen (\u003ca href=\"https://twitter.com/oleg008\" rel=\"nofollow\"\u003e@oleg008\u003c/a\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/article\u003e","loaded":true,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":[{"level":1,"text":"A thorough analysis of CSS-in-TS","anchor":"a-thorough-analysis-of-css-in-ts","htmlText":"A thorough analysis of CSS-in-TS"},{"level":2,"text":"Table of contents","anchor":"table-of-contents","htmlText":"Table of contents"},{"level":2,"text":"Motivation","anchor":"motivation","htmlText":"Motivation"},{"level":2,"text":"Goals","anchor":"goals","htmlText":"Goals"},{"level":2,"text":"Disclaimer","anchor":"disclaimer","htmlText":"Disclaimer"},{"level":2,"text":"Overview","anchor":"overview","htmlText":"Overview"},{"level":3,"text":"LEGEND:","anchor":"legend","htmlText":"LEGEND:"},{"level":4,"text":"1. Co-location","anchor":"1-co-location","htmlText":"1. Co-location"},{"level":4,"text":"2. DX","anchor":"2-dx","htmlText":"2. DX"},{"level":4,"text":"3. tag` ` (Tagged Templates)","anchor":"3-tag-tagged-templates","htmlText":"3. tag` ` (Tagged Templates)"},{"level":4,"text":"4. { } (Object Styles)","anchor":"4--object-styles","htmlText":"4. { } (Object Styles)"},{"level":4,"text":"5. TS","anchor":"5-ts","htmlText":"5. TS"},{"level":4,"text":"6. \u0026 ctx (Contextual Styles)","anchor":"6--ctx-contextual-styles","htmlText":"6. \u0026amp; ctx (Contextual Styles)"},{"level":4,"text":"7. Nesting","anchor":"7-nesting","htmlText":"7. Nesting"},{"level":4,"text":"8. Theming","anchor":"8-theming","htmlText":"8. Theming"},{"level":4,"text":"9. .css (Static CSS extraction)","anchor":"9-css-static-css-extraction","htmlText":"9. .css (Static CSS extraction)"},{"level":4,"text":"10. \u003cstyle\u003e tag","anchor":"10-style-tag","htmlText":"10. \u0026lt;style\u0026gt; tag"},{"level":4,"text":"11. Atomic CSS","anchor":"11-atomic-css","htmlText":"11. Atomic CSS"},{"level":4,"text":"12. className","anchor":"12-classname","htmlText":"12. className"},{"level":4,"text":"13. \u003cStyled /\u003e","anchor":"13-styled-","htmlText":"13. \u0026lt;Styled /\u0026gt;"},{"level":4,"text":"14. css prop","anchor":"14-css-prop","htmlText":"14. css prop"},{"level":4,"text":"15. Framework agnostic","anchor":"15-framework-agnostic","htmlText":"15. Framework agnostic"},{"level":4,"text":"16. Page size delta","anchor":"16-page-size-delta","htmlText":"16. Page size delta"},{"level":3,"text":"Overall observations","anchor":"overall-observations","htmlText":"Overall observations"},{"level":4,"text":"✅ Code splitting","anchor":"-code-splitting","htmlText":"✅ Code splitting"},{"level":4,"text":"✅ Global styles","anchor":"-global-styles","htmlText":"✅ Global styles"},{"level":4,"text":"✅ SSR","anchor":"-ssr","htmlText":"✅ SSR"},{"level":4,"text":"✅ Vendor prefixes","anchor":"-vendor-prefixes","htmlText":"✅ Vendor prefixes"},{"level":4,"text":"✅ Unique class names","anchor":"-unique-class-names","htmlText":"✅ Unique class names"},{"level":4,"text":"✅ No inline styles","anchor":"-no-inline-styles","htmlText":"✅ No inline styles"},{"level":4,"text":"✅ Full CSS support","anchor":"-full-css-support","htmlText":"✅ Full CSS support"},{"level":4,"text":"✅ Critical CSS extraction","anchor":"-critical-css-extraction","htmlText":"✅ Critical CSS extraction"},{"level":4,"text":"🟠 Performance Metrics","anchor":"-performance-metrics","htmlText":"🟠 Performance Metrics"},{"level":4,"text":"1. .css file extraction","anchor":"1-css-file-extraction","htmlText":"1. .css file extraction"},{"level":4,"text":"2. \u003cstyle\u003e tag injected styles","anchor":"2-style-tag-injected-styles","htmlText":"2. \u0026lt;style\u0026gt; tag injected styles"},{"level":4,"text":"🟠 Dead code removal","anchor":"-dead-code-removal","htmlText":"🟠 Dead code removal"},{"level":4,"text":"🟠 Debugging / Inspecting","anchor":"-debugging--inspecting","htmlText":"🟠 Debugging / Inspecting"},{"level":5,"text":"1. Using \u003cstyle\u003e tag(s)","anchor":"1-using-style-tags","htmlText":"1. Using \u0026lt;style\u0026gt; tag(s)"},{"level":5,"text":"2. Using CSSStyleSheet API","anchor":"2-using-cssstylesheet-api","htmlText":"2. Using CSSStyleSheet API"},{"level":4,"text":"❌ No component deduping","anchor":"-no-component-deduping","htmlText":"❌ No component deduping"},{"level":3,"text":"CSS Modules","anchor":"css-modules","htmlText":"CSS Modules"},{"level":3,"text":"Styled JSX","anchor":"styled-jsx","htmlText":"Styled JSX"},{"level":4,"text":"Other benefits","anchor":"other-benefits","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions","htmlText":"Conclusions"},{"level":3,"text":"Styled Components","anchor":"styled-components","htmlText":"Styled Components"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-1","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-1","htmlText":"Conclusions"},{"level":3,"text":"Emotion","anchor":"emotion","htmlText":"Emotion"},{"level":4,"text":"Other benefits","anchor":"other-benefits-1","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-2","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-2","htmlText":"Conclusions"},{"level":3,"text":"TypeStyle","anchor":"typestyle","htmlText":"TypeStyle"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-3","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-3","htmlText":"Conclusions"},{"level":3,"text":"Fela","anchor":"fela","htmlText":"Fela"},{"level":4,"text":"Other benefits","anchor":"other-benefits-2","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-4","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-4","htmlText":"Conclusions"},{"level":3,"text":"Stitches","anchor":"stitches","htmlText":"Stitches"},{"level":4,"text":"Other benefits","anchor":"other-benefits-3","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-5","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-5","htmlText":"Conclusions"},{"level":3,"text":"JSS","anchor":"jss","htmlText":"JSS"},{"level":4,"text":"Other benefits","anchor":"other-benefits-4","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-6","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-6","htmlText":"Conclusions"},{"level":3,"text":"Goober","anchor":"goober","htmlText":"Goober"},{"level":4,"text":"Other benefits","anchor":"other-benefits-5","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-7","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-7","htmlText":"Conclusions"},{"level":3,"text":"Compiled","anchor":"compiled","htmlText":"Compiled"},{"level":4,"text":"Other benefits","anchor":"other-benefits-6","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-8","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-8","htmlText":"Conclusions"},{"level":3,"text":"Linaria","anchor":"linaria","htmlText":"Linaria"},{"level":4,"text":"Other benefits","anchor":"other-benefits-7","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-9","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-9","htmlText":"Conclusions"},{"level":3,"text":"vanilla-extract","anchor":"vanilla-extract","htmlText":"vanilla-extract"},{"level":4,"text":"Other benefits","anchor":"other-benefits-8","htmlText":"Other benefits"},{"level":4,"text":"Worth mentioning observations","anchor":"worth-mentioning-observations-10","htmlText":"Worth mentioning observations"},{"level":4,"text":"Conclusions","anchor":"conclusions-10","htmlText":"Conclusions"},{"level":2,"text":"Libraries not included","anchor":"libraries-not-included","htmlText":"Libraries not included"},{"level":3,"text":"Treat","anchor":"treat","htmlText":"Treat"},{"level":3,"text":"style9","anchor":"style9","htmlText":"style9"},{"level":3,"text":"Tailwind","anchor":"tailwind","htmlText":"Tailwind"},{"level":3,"text":"Aphrodite","anchor":"aphrodite","htmlText":"Aphrodite"},{"level":3,"text":"Glamor","anchor":"glamor","htmlText":"Glamor"},{"level":3,"text":"Cxs","anchor":"cxs","htmlText":"Cxs"},{"level":3,"text":"Astroturf","anchor":"astroturf","htmlText":"Astroturf"},{"level":3,"text":"Otion","anchor":"otion","htmlText":"Otion"},{"level":3,"text":"Styletron","anchor":"styletron","htmlText":"Styletron"},{"level":3,"text":"Radium","anchor":"radium","htmlText":"Radium"},{"level":3,"text":"Glamorous","anchor":"glamorous","htmlText":"Glamorous"},{"level":2,"text":"Running the examples","anchor":"running-the-examples","htmlText":"Running the examples"},{"level":2,"text":"Feedback and Suggestions","anchor":"feedback-and-suggestions","htmlText":"Feedback and Suggestions"}],"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fandreipfeiffer%2Fcss-in-js"}}],"overviewFilesProcessingTime":0}},"appPayload":{"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-7d7eb7c71814.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-96e76d5fdb2c.js","githubDevUrl":null,"enabled_features":{"copilot_workspace":null,"code_nav_ui_events":false,"overview_shared_code_dropdown_button":false,"react_blob_overlay":false,"accessible_code_button":true,"github_models_repo_integration":false}}}}</script> <div data-target="react-partial.reactRoot"><style data-styled="true" data-styled-version="5.3.11">.iVEunk{margin-top:16px;margin-bottom:16px;}/*!sc*/ .jzuOtQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}/*!sc*/ .bGojzy{margin-bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;row-gap:16px;}/*!sc*/ .iNSVHo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-bottom:16px;padding-top:8px;}/*!sc*/ .bVgnfw{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:8px;}/*!sc*/ @media screen and (max-width:320px){.bVgnfw{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}}/*!sc*/ .CEgMp{position:relative;}/*!sc*/ @media screen and (max-width:380px){.CEgMp .ref-selector-button-text-container{max-width:80px;}}/*!sc*/ @media screen and (max-width:320px){.CEgMp{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}.CEgMp .overview-ref-selector{width:100%;}.CEgMp .overview-ref-selector > span{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;}.CEgMp .overview-ref-selector > span > span[data-component="text"]{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}}/*!sc*/ .gMOVLe[data-size="medium"]{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:0;}/*!sc*/ .gMOVLe[data-size="medium"] svg{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .gMOVLe[data-size="medium"] > span{width:inherit;}/*!sc*/ .gUkoLg{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .bZBlpz{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;}/*!sc*/ .lhTYNA{margin-right:4px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .ffLUq{font-size:14px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}/*!sc*/ .bmcJak{min-width:0;}/*!sc*/ .fLXEGX{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (max-width:1079px){.fLXEGX{display:none;}}/*!sc*/ .lmSMZJ[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));padding-left:4px;padding-right:4px;}/*!sc*/ .lmSMZJ[data-size="medium"] span[data-component="leadingVisual"]{margin-right:4px !important;}/*!sc*/ .dqfxud{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:1080px){.dqfxud{display:none;}}/*!sc*/ @media screen and (max-width:543px){.dqfxud{display:none;}}/*!sc*/ .fGwBZA[data-size="medium"][data-no-visuals]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .jxTzTd{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-left:8px;gap:8px;}/*!sc*/ .gqqBXN{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;}/*!sc*/ @media screen and (max-width:543px){.gqqBXN{display:none;}}/*!sc*/ .dzXgxt{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (max-width:1011px){.dzXgxt{display:none;}}/*!sc*/ .iWFGlI{margin-left:8px;margin-right:8px;margin:0;}/*!sc*/ .vcvyP{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:160px;}/*!sc*/ .YUPas{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:1012px){.YUPas{display:none;}}/*!sc*/ .izFOf{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:544px){.izFOf{display:none;}}/*!sc*/ .vIPPs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:16px;}/*!sc*/ .fdROMU{width:100%;border-collapse:separate;border-spacing:0;border:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;table-layout:fixed;overflow:unset;}/*!sc*/ .jGKpsv{height:0px;line-height:0px;}/*!sc*/ .jGKpsv tr{height:0px;font-size:0px;}/*!sc*/ .jdgHnn{padding:16px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:12px;text-align:left;height:40px;}/*!sc*/ .jdgHnn th{padding-left:16px;background-color:var(--bgColor-muted,var(--color-canvas-subtle,#f6f8fa));}/*!sc*/ .bQivRW{width:100%;border-top-left-radius:6px;}/*!sc*/ @media screen and (min-width:544px){.bQivRW{display:none;}}/*!sc*/ .ldkMIO{width:40%;border-top-left-radius:6px;}/*!sc*/ @media screen and (max-width:543px){.ldkMIO{display:none;}}/*!sc*/ .jMbWeI{text-align:right;padding-right:16px;width:136px;border-top-right-radius:6px;}/*!sc*/ .gpqjiB{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:12px;height:40px;}/*!sc*/ .dzCJzi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;min-width:273px;padding:8px;}/*!sc*/ @media screen and (min-width:544px){.dzCJzi{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}/*!sc*/ .eNCcrz{text-align:center;vertical-align:center;height:40px;border-top:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));}/*!sc*/ .bHTcCe{border-top:1px solid var(--borderColor-default,var(--color-border-default));cursor:pointer;}/*!sc*/ .csrIcr{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;gap:16px;}/*!sc*/ .bUQNHB{border:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}/*!sc*/ @media screen and (max-width:543px){.bUQNHB{margin-left:-16px;margin-right:-16px;max-width:calc(100% + 32px);}}/*!sc*/ @media screen and (min-width:544px){.bUQNHB{max-width:100%;}}/*!sc*/ .jPdcfu{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-bottom-color:var(--borderColor-default,var(--color-border-default,#d0d7de));-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-right:8px;position:-webkit-sticky;position:sticky;top:0;background-color:var(--bgColor-default,var(--color-canvas-default,#ffffff));z-index:1;border-top-left-radius:6px;border-top-right-radius:6px;}/*!sc*/ .iphEWz{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;border-bottom:none;max-width:100%;padding-left:8px;padding-right:8px;}/*!sc*/ .hUCRAk{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .cwoBXV[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-subtle,#6e7781));padding-left:8px;padding-right:8px;}/*!sc*/ .QkQOb{padding:32px;overflow:auto;}/*!sc*/ data-styled.g1[id="Box-sc-g0xbh4-0"]{content:"iVEunk,jzuOtQ,bGojzy,iNSVHo,bVgnfw,CEgMp,gMOVLe,gUkoLg,bZBlpz,lhTYNA,ffLUq,bmcJak,fLXEGX,lmSMZJ,dqfxud,fGwBZA,jxTzTd,gqqBXN,dzXgxt,iWFGlI,vcvyP,YUPas,izFOf,vIPPs,fdROMU,jGKpsv,jdgHnn,bQivRW,ldkMIO,jMbWeI,gpqjiB,dzCJzi,eNCcrz,bHTcCe,csrIcr,bUQNHB,jPdcfu,iphEWz,hUCRAk,cwoBXV,QkQOb,"}/*!sc*/ .brGdpi{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;-webkit-clip:rect(0,0,0,0);clip:rect(0,0,0,0);white-space:nowrap;border-width:0;}/*!sc*/ data-styled.g6[id="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0"]{content:"brGdpi,"}/*!sc*/ .hWlpPn{position:relative;display:inline-block;}/*!sc*/ .hWlpPn::after{position:absolute;z-index:1000000;display:none;padding:0.5em 0.75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;-webkit-text-decoration:none;text-decoration:none;text-shadow:none;text-transform:none;-webkit-letter-spacing:normal;-moz-letter-spacing:normal;-ms-letter-spacing:normal;letter-spacing:normal;word-wrap:break-word;white-space:pre;pointer-events:none;content:attr(aria-label);background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;opacity:0;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .hWlpPn:hover::after,.hWlpPn:active::after,.hWlpPn:focus::after,.hWlpPn:focus-within::after{display:inline-block;-webkit-text-decoration:none;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-no-delay:hover::after,.hWlpPn.tooltipped-no-delay:active::after,.hWlpPn.tooltipped-no-delay:focus::after,.hWlpPn.tooltipped-no-delay:focus-within::after{-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-multiline:hover::after,.hWlpPn.tooltipped-multiline:active::after,.hWlpPn.tooltipped-multiline:focus::after,.hWlpPn.tooltipped-multiline:focus-within::after{display:table-cell;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-se::after,.hWlpPn.tooltipped-sw::after{top:100%;right:50%;margin-top:6px;}/*!sc*/ .hWlpPn.tooltipped-se::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-sw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-n::after,.hWlpPn.tooltipped-ne::after,.hWlpPn.tooltipped-nw::after{right:50%;bottom:100%;margin-bottom:6px;}/*!sc*/ .hWlpPn.tooltipped-ne::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-nw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-n::after{-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);}/*!sc*/ .hWlpPn.tooltipped-w::after{right:100%;bottom:50%;margin-right:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-e::after{bottom:50%;left:100%;margin-left:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-multiline::after{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:250px;word-wrap:break-word;white-space:pre-line;border-collapse:separate;}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-s::after,.hWlpPn.tooltipped-multiline.tooltipped-n::after{right:auto;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-w::after,.hWlpPn.tooltipped-multiline.tooltipped-e::after{right:100%;}/*!sc*/ .hWlpPn.tooltipped-align-right-2::after{right:0;margin-right:0;}/*!sc*/ .hWlpPn.tooltipped-align-left-2::after{left:0;margin-left:0;}/*!sc*/ data-styled.g17[id="Tooltip__TooltipBase-sc-17tf59c-0"]{content:"hWlpPn,"}/*!sc*/ .liVpTx{display:inline-block;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap;max-width:125px;}/*!sc*/ data-styled.g19[id="Truncate__StyledTruncate-sc-23o1d2-0"]{content:"liVpTx,"}/*!sc*/ </style> <!-- --> <!-- --> <div class="Box-sc-g0xbh4-0 iVEunk"><div class="Box-sc-g0xbh4-0 jzuOtQ"><div class="Box-sc-g0xbh4-0 bGojzy"></div></div><div class="Box-sc-g0xbh4-0 iNSVHo"><div class="Box-sc-g0xbh4-0 bVgnfw"><div class="Box-sc-g0xbh4-0 CEgMp"><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" class="Box-sc-g0xbh4-0 gMOVLe prc-Button-ButtonBase-c50BI overview-ref-selector width-full" data-loading="false" data-size="medium" data-variant="default" aria-describedby="branch-picker-repos-header-ref-selector-loading-announcement" id="branch-picker-repos-header-ref-selector"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x"><div class="Box-sc-g0xbh4-0 bZBlpz"><div class="Box-sc-g0xbh4-0 lhTYNA"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></div><div class="Box-sc-g0xbh4-0 ffLUq ref-selector-button-text-container"><span class="Box-sc-g0xbh4-0 bmcJak prc-Text-Text-0ima0"> <!-- -->main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><button hidden="" data-hotkey-scope="read-only-cursor-text-area"></button></div><div class="Box-sc-g0xbh4-0 fLXEGX"><a style="--button-color:fg.muted" type="button" href="/andreipfeiffer/css-in-js/branches" class="Box-sc-g0xbh4-0 lmSMZJ prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rclab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Branches</span></span></a><a style="--button-color:fg.muted" type="button" href="/andreipfeiffer/css-in-js/tags" class="Box-sc-g0xbh4-0 lmSMZJ prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rklab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-tag" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Tags</span></span></a></div><div class="Box-sc-g0xbh4-0 dqfxud"><a style="--button-color:fg.muted" type="button" aria-label="Go to Branches page" href="/andreipfeiffer/css-in-js/branches" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":Relab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></a><a style="--button-color:fg.muted" type="button" aria-label="Go to Tags page" href="/andreipfeiffer/css-in-js/tags" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":Rmlab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-tag" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path></svg></a></div></div><div class="Box-sc-g0xbh4-0 jxTzTd"><div class="Box-sc-g0xbh4-0 gqqBXN"><div class="Box-sc-g0xbh4-0 dzXgxt"><!--$--><div class="Box-sc-g0xbh4-0 iWFGlI"><span class="Box-sc-g0xbh4-0 vcvyP TextInput-wrapper prc-components-TextInputWrapper-i1ofR prc-components-TextInputBaseWrapper-ueK9q" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id=":R2j5ab:" aria-hidden="true"><svg aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellcheck="false" placeholder="Go to file" aria-describedby=":R2j5ab: :R2j5abH1:" data-component="input" class="prc-components-Input-Ic-y8" value=""/><span class="TextInput-icon" id=":R2j5abH1:" aria-hidden="true"></span></span></div><!--/$--></div><div class="Box-sc-g0xbh4-0 YUPas"><button type="button" class="prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":Rr5ab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x">Go to file</span></span></button></div><div class="react-directory-add-file-icon"></div><div class="react-directory-remove-file-icon"></div></div><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="primary" aria-describedby=":R55ab:-loading-announcement" id=":R55ab:"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-code hide-sm" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Code</span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="Box-sc-g0xbh4-0 izFOf"><button data-component="IconButton" type="button" aria-label="Open more actions menu" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R75ab:-loading-announcement" id=":R75ab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button></div></div></div><div class="Box-sc-g0xbh4-0 vIPPs"><div data-hpc="true"><button hidden="" data-testid="focus-next-element-button" data-hotkey="j"></button><button hidden="" data-testid="focus-previous-element-button" data-hotkey="k"></button><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading" id="folders-and-files">Folders and files</h2><table aria-labelledby="folders-and-files" class="Box-sc-g0xbh4-0 fdROMU"><thead class="Box-sc-g0xbh4-0 jGKpsv"><tr class="Box-sc-g0xbh4-0 jdgHnn"><th colSpan="2" class="Box-sc-g0xbh4-0 bQivRW"><span class="text-bold">Name</span></th><th colSpan="1" class="Box-sc-g0xbh4-0 ldkMIO"><span class="text-bold">Name</span></th><th class="hide-sm"><div title="Last commit message" class="Truncate__StyledTruncate-sc-23o1d2-0 liVpTx width-fit"><span class="text-bold">Last commit message</span></div></th><th colSpan="1" class="Box-sc-g0xbh4-0 jMbWeI"><div title="Last commit date" class="Truncate__StyledTruncate-sc-23o1d2-0 liVpTx width-fit"><span class="text-bold">Last commit date</span></div></th></tr></thead><tbody><tr class="Box-sc-g0xbh4-0 gpqjiB"><td colSpan="3" class="bgColor-muted p-1 rounded-top-2"><div class="Box-sc-g0xbh4-0 dzCJzi"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">History</h2><a href="/andreipfeiffer/css-in-js/commits/main/" class="prc-Button-ButtonBase-c50BI d-none d-lg-flex LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":Raqj8pab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x"><span class="fgColor-default">337 Commits</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><span role="tooltip" aria-label="337 Commits" id="history-icon-button-tooltip" class="Tooltip__TooltipBase-sc-17tf59c-0 hWlpPn tooltipped-n"><a href="/andreipfeiffer/css-in-js/commits/main/" class="prc-Button-ButtonBase-c50BI LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":R1iqj8pab:-loading-announcement history-icon-button-tooltip"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a></span></div></div></div></div></td></tr><tr class="react-directory-row undefined" id="folder-row-0"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="This path skips through empty directories" aria-label=".yarn/releases, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/.yarn/releases"><span class="react-directory-default-color" data-testid="path-name-segment">.yarn/</span><span class="" data-testid="path-name-segment">releases</span></a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="This path skips through empty directories" aria-label=".yarn/releases, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/.yarn/releases"><span class="react-directory-default-color" data-testid="path-name-segment">.yarn/</span><span class="" data-testid="path-name-segment">releases</span></a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-1"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="This path skips through empty directories" aria-label="components/demo, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/components/demo"><span class="react-directory-default-color" data-testid="path-name-segment">components/</span><span class="" data-testid="path-name-segment">demo</span></a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="This path skips through empty directories" aria-label="components/demo, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/components/demo"><span class="react-directory-default-color" data-testid="path-name-segment">components/</span><span class="" data-testid="path-name-segment">demo</span></a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-2"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="pages" aria-label="pages, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/pages">pages</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="pages" aria-label="pages, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/pages">pages</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-3"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="public" aria-label="public, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/public">public</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="public" aria-label="public, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/public">public</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-4"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="styles" aria-label="styles, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/styles">styles</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="styles" aria-label="styles, (Directory)" class="Link--primary" href="/andreipfeiffer/css-in-js/tree/main/styles">styles</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-5"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitattributes" aria-label=".gitattributes, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/.gitattributes">.gitattributes</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitattributes" aria-label=".gitattributes, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/.gitattributes">.gitattributes</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-6"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitignore" aria-label=".gitignore, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/.gitignore">.gitignore</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitignore" aria-label=".gitignore, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/.gitignore">.gitignore</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-7"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".yarnrc" aria-label=".yarnrc, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/.yarnrc">.yarnrc</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".yarnrc" aria-label=".yarnrc, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/.yarnrc">.yarnrc</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-8"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="README.md" aria-label="README.md, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/README.md">README.md</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="README.md" aria-label="README.md, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/README.md">README.md</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-9"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="next-env.d.ts" aria-label="next-env.d.ts, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/next-env.d.ts">next-env.d.ts</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="next-env.d.ts" aria-label="next-env.d.ts, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/next-env.d.ts">next-env.d.ts</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-10"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="package.json" aria-label="package.json, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/package.json">package.json</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="package.json" aria-label="package.json, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/package.json">package.json</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-11"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="tsconfig.json" aria-label="tsconfig.json, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/tsconfig.json">tsconfig.json</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="tsconfig.json" aria-label="tsconfig.json, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/tsconfig.json">tsconfig.json</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-12"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="yarn.lock" aria-label="yarn.lock, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/yarn.lock">yarn.lock</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="yarn.lock" aria-label="yarn.lock, (File)" class="Link--primary" href="/andreipfeiffer/css-in-js/blob/main/yarn.lock">yarn.lock</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="Box-sc-g0xbh4-0 eNCcrz show-for-mobile" data-testid="view-all-files-row"><td colSpan="3" class="Box-sc-g0xbh4-0 bHTcCe"><div><button class="prc-Link-Link-85e08">View all files</button></div></td></tr></tbody></table></div><div class="Box-sc-g0xbh4-0 csrIcr"><div class="Box-sc-g0xbh4-0 bUQNHB"><div itemscope="" itemType="https://schema.org/abstract" class="Box-sc-g0xbh4-0 jPdcfu"><h2 class="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0 brGdpi">Repository files navigation</h2><nav class="Box-sc-g0xbh4-0 iphEWz prc-components-UnderlineWrapper-oOh5J" aria-label="Repository files"><ul class="prc-components-UnderlineItemList-b23Hf" role="list"><li class="Box-sc-g0xbh4-0 hUCRAk"><a class="prc-components-UnderlineItem-lJsg-" href="#" aria-current="page"><span data-component="icon"><svg aria-hidden="true" focusable="false" class="octicon octicon-book" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path></svg></span><span data-component="text" data-content="README">README</span></a></li></ul></nav><button style="--button-color:fg.subtle" type="button" aria-label="Outline" aria-haspopup="true" aria-expanded="false" tabindex="0" class="Box-sc-g0xbh4-0 cwoBXV prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rr9ab:-loading-announcement" id=":Rr9ab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button></div><div class="Box-sc-g0xbh4-0 QkQOb js-snippet-clipboard-copy-unpositioned undefined" data-hpc="true"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">A thorough analysis of CSS-in-TS</h1><a id="user-content-a-thorough-analysis-of-css-in-ts" class="anchor" aria-label="Permalink: A thorough analysis of CSS-in-TS" href="#a-thorough-analysis-of-css-in-ts"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This document contains an in-depth analysis of all the current <strong>CSS-in-JS</strong> solutions, that support <strong>Server Side Rendering</strong> and <strong>TypeScript</strong>.</p> <p dir="auto">The baseline reference we'll use for comparison is a <strong>CSS Modules</strong> approach.<br> We're using <strong>Next.js</strong> as a SSR framework for building resources.<br> Last important aspect is type-safety with full <strong>TypeScript</strong> support.</p> <br> <blockquote> <p dir="auto">🗓 <em>Last update: <strong>Aug 2021</strong></em></p> </blockquote> <blockquote> <p dir="auto">🗞 To get a shorter overview, you can checkout the <strong>article on CSS Tricks</strong>:<br> <a href="https://css-tricks.com/a-thorough-analysis-of-css-in-js/" rel="nofollow">https://css-tricks.com/a-thorough-analysis-of-css-in-js/</a></p> </blockquote> <blockquote> <p dir="auto">📽 If you prefer a video instead, you can checkout my <strong>talk from ngPartyCZ</strong>:<br> <a href="https://www.youtube.com/watch?v=c7uWGhrAx9A" rel="nofollow">https://www.youtube.com/watch?v=c7uWGhrAx9A</a></p> </blockquote> <blockquote> <p dir="auto">✋ Please checkout our <a href="#goals">goals</a> & <a href="#disclaimer">disclaimer</a> before jumping to conclusions.</p> </blockquote> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Table of contents</h2><a id="user-content-table-of-contents" class="anchor" aria-label="Permalink: Table of contents" href="#table-of-contents"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li><a href="#motivation">Motivation</a></li> <li><a href="#goals">Goals</a></li> <li><a href="#disclaimer">Disclaimer</a></li> <li><a href="#overview"><strong>Overview</strong></a> <ul dir="auto"> <li><a href="#legend">Legend</a></li> <li><a href="#overall-observations">Overall observations</a></li> </ul> </li> <li>Libraries review <ul dir="auto"> <li><a href="#css-modules"><strong>CSS Modules</strong></a></li> <li><a href="#styled-jsx"><strong>Styled JSX</strong></a></li> <li><a href="#styled-components"><strong>Styled Components</strong></a></li> <li><a href="#emotion"><strong>Emotion</strong></a></li> <li><a href="#typestyle"><strong>TypeStyle</strong></a></li> <li><a href="#fela"><strong>Fela</strong></a></li> <li><a href="#stitches"><strong>Stitches</strong></a></li> <li><a href="#jss"><strong>JSS</strong></a></li> <li><a href="#goober"><strong>Goober</strong></a></li> <li><a href="#compiled"><strong>Compiled</strong></a></li> <li><a href="#linaria"><strong>Linaria</strong></a></li> <li><a href="#vanilla-extract"><strong>vanilla-extract</strong></a></li> </ul> </li> <li><a href="#libraries-not-included">Libraries not included</a></li> <li><a href="#running-the-examples">Running the examples</a></li> <li><a href="#feedback-and-suggestions">Feedback and Suggestions</a></li> </ul> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Motivation</h2><a id="user-content-motivation" class="anchor" aria-label="Permalink: Motivation" href="#motivation"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The <strong>CSS language</strong> and <strong>CSS Modules</strong> have some limitations, especially if we want to have type-safe code. Some of these limitations have alterative solutions, others are just being <em>annoying</em> or <em>less than ideal</em>:</p> <ol dir="auto"> <li> <p dir="auto"><strong>Styles cannot be co-located with components</strong><br> This can be frustrating when authoring many small components, but it's not a deal breaker. However, the experience of moving back-and-forth between the <code>component.js</code> file and the <code>component.css</code> file, searching for a given class name, and not being able to easily <em>"go to style definition"</em>, is an important productivity drawback.</p> </li> <li> <p dir="auto"><strong>Styling pseudos and media queries requires selector duplication</strong><br> Another frustrating fact is the need to duplicate our CSS classes when defining <strong>pseudo classes and elements</strong>, or <strong>media queries</strong>. We can overcome these limitations using a CSS preprocessor like <strong>SASS, LESS or Stylus</strong>, that supports the <code>&</code> parent selector, enabling <strong>contextual styling</strong>.</p> <div class="highlight highlight-source-css notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content=".button {} /* duplicated selector declaration for pseudo classes/elements */ .button:hover {} .button::after {} @media (min-width: 640px) { /* duplicated selector declaration inside media queries */ .button {} }"><pre>.<span class="pl-c1">button</span> {} <span class="pl-c">/* duplicated selector declaration for pseudo classes/elements */</span> .<span class="pl-c1">button</span><span class="pl-kos">:</span><span class="pl-c1">hover</span> {} .<span class="pl-c1">button</span>::<span class="pl-c1">after</span> {} <span class="pl-k">@media</span> (<span class="pl-c1">min-width</span><span class="pl-kos">:</span> <span class="pl-c1">640<span class="pl-smi">px</span></span>) { <span class="pl-c">/* duplicated selector declaration inside media queries */</span> .<span class="pl-c1">button</span> {} }</pre></div> </li> <li> <p dir="auto"><strong>Styles usage is disconnected from their definition</strong><br> We get no IntelliSense with CSS Modules, of what CSS classes are defined in the <code>component.css</code> file, making <strong>copy-paste</strong> a required tool, lowering the DX. It also makes <strong>refactoring very cumbersome</strong>, because of the lack of safety.</p> </li> <li> <p dir="auto"><strong>Using type-safe design tokens in CSS is non-trivial</strong><br> Any <a href="https://spectrum.adobe.com/page/design-tokens/" rel="nofollow">design tokens</a> defined in JS/TS (to benefit from type-safety) cannot be directly used in CSS.</p> <p dir="auto">There are at least 2 workarounds for this issue, neither of them being elegant:</p> <ul dir="auto"> <li>We could inject them as <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="nofollow">CSS Custom Properties / Variables</a>, but we still don't get any IntelliSense or type-safety when using them in <code>.module.css</code>.</li> <li>We could use <strong>inline styles</strong>, which is less performant, and it also introduces a different way to write styles (camelCase vs. kebab-case), while also splitting the styling in 2 different places: the component file and the <code>.css</code> file.</li> <li>We could use CSS (or SASS) as the source of truth for design tokens, by storing them as CSS Custom Properties and read them from JS using DOM queries, but we'd still need to manually update both the CSS and JS code when we perform any change, because we don't have type-safety when dealing with CSS;</li> </ul> </li> </ol> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Goals</h2><a id="user-content-goals" class="anchor" aria-label="Permalink: Goals" href="#goals"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">There are specific goals we're looking for with this analysis:</p> <ul dir="auto"> <li>🥇 SSR support and easy integration with Next.js</li> <li>🥇 full TypeScript support</li> <li>🥇 great DX with code completion & syntax highlight</li> <li>🥈 light-weight</li> <li>🥈 comprehensive documentation</li> <li>🥉 intuitive API and low learning curve</li> </ul> <br> <p dir="auto">Getting even more specific, we wanted to experience the usage of various CSS-in-JS solutions regarding:</p> <ul dir="auto"> <li>defining <strong>global styles</strong></li> <li>using <strong>media queries</strong> & <strong>pseudo classes</strong></li> <li><strong>dynamic styles</strong> based on component <code>props</code> (aka. component variants), or from user input</li> <li><strong>bundle size</strong> impact</li> </ul> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Disclaimer</h2><a id="user-content-disclaimer" class="anchor" aria-label="Permalink: Disclaimer" href="#disclaimer"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This analysis is intended to be <strong>objective</strong> and <strong>unopinionated</strong>:</p> <ul dir="auto"> <li>I have not built my own CSS-in-JS library.</li> <li>I don't work on any of the libraries reviewed here.</li> <li>I have <strong>no intention or motivation for <em>promoting</em> or <em>trashing</em></strong> either of them.</li> <li>I have <strong>no prior experience</strong> with any CSS-in-JS solution, so I'm <strong>not biased</strong> towards any of them.</li> <li>I have <strong>equally used</strong> all the solutions analyzed here, which also means I have <strong>no extensive experience</strong> with any of them. So, you can safely say <em>I'm a jack of all <del>trades</del> CSS-in-JS libraries, but master of none</em>.</li> </ul> <br> <p dir="auto">👎 <strong>What you WON'T FIND here?</strong></p> <ul dir="auto"> <li>which solution is <em>"the best"</em>, as I'll not add any grading, which would also be highly subjective;</li> <li>which solution is <em>"the fastest"</em>, as I'm not concearned about rendering performance metrics (you can checkout <a href="https://necolas.github.io/react-native-web/benchmarks/" rel="nofollow">Necholas's benchmarks</a> for this);</li> </ul> <br> <p dir="auto">👍 <strong>What you WILL FIND here?</strong></p> <ul dir="auto"> <li>an overview of (almost) all CSS-in-JS solutions available at this date (see <em>last update</em> on top) that we've tried to integrate into a <strong>Next.js v11 + TypeScript</strong> empty project, with <strong>minimal effort</strong>;</li> <li>a limited set of <strong>quantitative metrics</strong> that allowed us to evaluate these solutions, which might help you as well;</li> <li>an additional list of <strong>qualitative personal observations</strong>, which might be either minor details or deal-breakers when choosing a particular solution.</li> </ul> <p dir="auto">The libraries are not presented in any particular order. If you're interested in a brief <strong>history of CSS-in-JS</strong>, you should checkout the <a href="https://www.youtube.com/watch?v=75kmPj_iUOA" rel="nofollow">Past, Present, and Future of CSS-in-JS</a> insightful talk by Max Stoiber.</p> <hr> <br> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Overview</h2><a id="user-content-overview" class="anchor" aria-label="Permalink: Overview" href="#overview"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="center"><a href="#1-co-location">1. Co‑location</a></th> <th align="center"><a href="#2-dx">2. DX</a></th> <th align="center"><a href="#3-tag-tagged-templates">3. <code>tag` `</code></a></th> <th align="center"><a href="#4--object-styles">4. <code>{ }</code></a></th> <th align="center"><a href="#5-ts">5. TS</a></th> <th align="center"><a href="#6--ctx-contextual-styles">6. <code>&</code> ctx</a></th> <th align="center"><a href="#7-nesting">7. Nesting</a></th> <th align="center"><a href="#8-theming">8. Theme</a></th> <th align="center"><a href="#9-css-static-css-extraction">9. <code>.css</code></a></th> <th align="center"><a href="#10-style-tag">10. <code><style></code></a></th> <th align="center"><a href="#11-atomic-css">11. Atomic</a></th> <th align="center"><a href="#12-classname">12. <code>className</code></a></th> <th align="center"><a href="#13-styled-">13. <code><Styled /></code></a></th> <th align="center"><a href="#14-css-prop">14. <code>css</code> prop</a></th> <th align="center"><a href="#15-framework-agnostic">15. Agnostic</a></th> <th align="right"><a href="#16-page-size-delta">16. Page size delta</a></th> </tr> </thead> <tbody> <tr> <td align="left"><a href="#css-modules">CSS Modules</a></td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="right">-</td> </tr> <tr> <td align="left"><a href="#styled-jsx">Styled JSX</a></td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">🟠</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">❌</td> <td align="right"><code>+2.8 kB / +12.0 kB</code></td> </tr> <tr> <td align="left"><a href="#styled-components">Styled Components</a></td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="right"><code>+13.4 kB / +39.0 kB</code></td> </tr> <tr> <td align="left"><a href="#emotion">Emotion</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="right"><code>+6.5 kB / +20.0 kB</code></td> </tr> <tr> <td align="left"><a href="#typestyle">TypeStyle</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="right"><code>+2.1 kB / +8.0 kB</code></td> </tr> <tr> <td align="left"><a href="#fela">Fela</a></td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="right"><code>+11.9 kB / +43.0 kB</code></td> </tr> <tr> <td align="left"><a href="#stitches">Stitches</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="right"><code>+5.3 kB / +17.0 kB</code></td> </tr> <tr> <td align="left"><a href="#jss">JSS</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">❌</td> <td align="center">✅</td> <td align="right"><code>+18.2 kB / +60.0 kB</code></td> </tr> <tr> <td align="left"><a href="#goober">Goober</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="right"><code>+1.1 kB / +4.0 kB</code></td> </tr> <tr> <td align="left"><a href="#compiled">Compiled</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="right"><code>+3.5 kB / +9.0 kB</code></td> </tr> <tr> <td align="left"><a href="#linaria">Linaria</a></td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="right"><code>+2.7 kB / +6.0 kB</code></td> </tr> <tr> <td align="left"><a href="#vanilla-extract">vanilla-extract</a></td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">✅</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">🟠</td> <td align="center">✅</td> <td align="center">❌</td> <td align="center">❌</td> <td align="center">✅</td> <td align="right"><code>+0.0 kB / -2.0 kB</code></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">LEGEND:</h3><a id="user-content-legend" class="anchor" aria-label="Permalink: LEGEND:" href="#legend"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>✅ - full & out-of-the-box support</li> <li>🟠 - partial or limited support, less than ideal, or requiring some additional manual work for full support</li> <li>❌ - lack of support</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">1. Co-location</h4><a id="user-content-1-co-location" class="anchor" aria-label="Permalink: 1. Co-location" href="#1-co-location"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The ability to define styles within the same file as the component. Note that we can also extract the styles into a separate file and import them, in case we prefer it.</p> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">2. DX</h4><a id="user-content-2-dx" class="anchor" aria-label="Permalink: 2. DX" href="#2-dx"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Refers to the <strong>Developer eXperience</strong> which includes 2 main aspects:</p> <ul dir="auto"> <li><strong>syntax highlighting</strong> for styles definition;</li> <li><strong>code-completion/suggestions</strong> for supported CSS Properties and available values (we're evaluating only the suggestion feature, not type-safety);</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">3. <code>tag` `</code> (Tagged Templates)</h4><a id="user-content-3-tag-tagged-templates" class="anchor" aria-label="Permalink: 3. tag` ` (Tagged Templates)" href="#3-tag-tagged-templates"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Support for defining <strong>styles as strings</strong>, using ES Tagged Templates:</p> <ul dir="auto"> <li>uses <code>kebab-case</code> for property names, just like plain CSS syntax;</li> <li>enables easier migration from plain CSS to CSS-in-JS, because we don't have to completely re-write the styles;</li> <li>requires installing additional code editor plugin(s) for <a href="#2-dx">syntax highlight and code completion</a>, otherwise our code would look like a plain <code>string</code>;</li> <li>requires an additional step to parse the string and convert it to JS, which can be done either at built time (slower builds), or at runtime (slightly larger payload);</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">4. <code>{ }</code> (Object Styles)</h4><a id="user-content-4--object-styles" class="anchor" aria-label="Permalink: 4. { } (Object Styles)" href="#4--object-styles"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Support for defining <strong>styles as objects</strong>, using plain JavaScript objects:</p> <ul dir="auto"> <li>uses <code>camelCase</code> for property names, like we would do in <a href="https://reactnative.dev/docs/next/style" rel="nofollow">React Native</a>;</li> <li>migrating existing CSS requires a complete rewrite (don't know how we could automate this);</li> <li>we don't need additional tooling for syntax highlighting, as we get it out-of-the-box, by writting JS objects;</li> <li>without proper TS definitions shipped with the library, we won't get code completion (☝️ we're only interested in TS, not Flow);</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">5. TS</h4><a id="user-content-5-ts" class="anchor" aria-label="Permalink: 5. TS" href="#5-ts"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">TypeScript support, either built-in, or via <code>@types</code> package, which should include:</p> <ul dir="auto"> <li>typings for the library API;</li> <li>Style Object typings (in case the library supports the object syntax);</li> <li><code>Props</code> generics, where applicable (get type-safe access to component props types when defining dynamic styles);</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">6. <code>&</code> ctx (Contextual Styles)</h4><a id="user-content-6--ctx-contextual-styles" class="anchor" aria-label="Permalink: 6. & ctx (Contextual Styles)" href="#6--ctx-contextual-styles"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Support for <strong>contextual styles</strong> allowing us to easily define <strong>pseudo classes & elements</strong> and <strong>media queries</strong> without the need to repeat the selector, as required in plain CSS:</p> <ul dir="auto"> <li>can either support the SASS/LESS/Stylus <code>&</code> parent selector;</li> <li>or provide any specific API or syntax to achieve the same result;</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">7. Nesting</h4><a id="user-content-7-nesting" class="anchor" aria-label="Permalink: 7. Nesting" href="#7-nesting"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Support for <strong>arbitrary nested selectors</strong>:</p> <ul dir="auto"> <li>this feature allows for great flexibility, which might be useful, or required in some specific use-cases;</li> <li>to keep in mind that it also introduces too many ways of defining styles, which might cause chaos if we want to enforce good-practices, scalability and maintainability;</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">8. Theming</h4><a id="user-content-8-theming" class="anchor" aria-label="Permalink: 8. Theming" href="#8-theming"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Built-in support for Theming or managing tokens for a design system.<br> We <strong>haven't tested out this feature</strong>, so we're only taking notes which libraries express their support in their docs.</p> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">9. <code>.css</code> (Static CSS extraction)</h4><a id="user-content-9-css-static-css-extraction" class="anchor" aria-label="Permalink: 9. .css (Static CSS extraction)" href="#9-css-static-css-extraction"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Defined styles are extracted as static <code>.css</code> files:</p> <ul dir="auto"> <li>it reduces the total bundle/page size, because we don't need additional runtime library, for injecting and evaluating the styles;</li> <li>this approach <a href="#-performance-metrics">affects <strong>FCP/FMP</strong></a> metrics negatively when users have an empty cache, and positively when having full cache;</li> <li>dynamic styling could potentially increase the generated file, because all style combinations must be pre-generated at built time;</li> <li>more suitable for less interactive solutions, where we serve a lot of different pages and we want to take advantage of cached styles (ie: e-commerce, blogs);</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">10. <code><style></code> tag</h4><a id="user-content-10-style-tag" class="anchor" aria-label="Permalink: 10. <style> tag" href="#10-style-tag"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Defined styles are injected inside <code><style></code> tags in the document's <code><head></code>:</p> <ul dir="auto"> <li>makes dynamic styling super easy;</li> <li>incurs larger payload, because we're also shipping a runtime library to handle dynamic styles;</li> <li>when using SSR, styles required for the initial render are shipped twice to the client: once during SSR, and again during <a href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web#rehydration-issues" rel="nofollow">hydration</a>;</li> <li>more suited for highly dynamic and interactive (single page) applications;</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">11. Atomic CSS</h4><a id="user-content-11-atomic-css" class="anchor" aria-label="Permalink: 11. Atomic CSS" href="#11-atomic-css"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The ability to generate <strong>atomic css classes</strong>, thus increasing style reusability, and reducing duplication:</p> <ul dir="auto"> <li>this generates a separate CSS class for each CSS property;</li> <li>we'll get larger HTML files, because each element will contain a larger number of CSS classes applied;</li> <li>theoretically <a href="https://sebastienlorber.com/atomic-css-in-js" rel="nofollow">atomic CSS-in-JS</a> reduces the scaling factor of our styles, <a href="https://www.youtube.com/watch?v=9JZHodNR184" rel="nofollow">Facebook is doing it</a> as well;</li> <li>it's debatable if the CSS total size reduction, is greater than the HTML size increase (what is the final delta)</li> <li>theoretically, if the class names are shorter than the CSS property definition, the delta is positive so we're shipping less bytes (also depends a lot on compression, so not easy to draw a definite conclusion);</li> <li>however, we're basically moving part of bytes from CSS to HTML, which might be harder to cache if we have dynamic SSRed pages;</li> <li>also, depends a lot on what changes more frequently: the styles? or the markup?</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">12. <code>className</code></h4><a id="user-content-12-classname" class="anchor" aria-label="Permalink: 12. className" href="#12-classname"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The library API returns a <code>string</code> which we have to add to our component or element;</p> <ul dir="auto"> <li>this is similar how we would normally style React components, so it's easy to adopt because we don't have to learn a new way of dealing with styles;</li> <li>to combine styles we have to use string concatenation;</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">13. <code><Styled /></code></h4><a id="user-content-13-styled-" class="anchor" aria-label="Permalink: 13. <Styled />" href="#13-styled-"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The API creates a wrapper (or <code>Styled</code>) component which includes the generated <code>className</code>(s):</p> <ul dir="auto"> <li>this technique was first introduced and popularized by <a href="#styled-components">Styled Components</a>, hence the name;</li> <li>we'll have to learn a new way to define styles, because we're not applying styles to elements, instead we're creating new components that include the styled elements;</li> <li>this also introduces a bit of indiretion when figuring out what native elements gets rendered inside a larger component;</li> <li>we end up creating components like <code>StyledButton</code> or <code>StyledList</code> instead of constants like <code>button_styles</code> or <code>list_styles</code>, so regarding naming it's pretty much the same thing;</li> <li>since the styles/class names are not re-used (we re-use the entire component), it makes sense to encapsulate the styles within the component and not think about 2 different aspects of the same entity;</li> <li>it's not React specific, can also be used with <a href="https://github.com/styled-components/vue-styled-components">Vue</a>;</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">14. <code>css</code> prop</h4><a id="user-content-14-css-prop" class="anchor" aria-label="Permalink: 14. css prop" href="#14-css-prop"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Allows passing styles using a special <code>css</code> prop, similar how we would define inline styles, but the library generates a unique CSS class name behind the scenes:</p> <ul dir="auto"> <li>it's a convenient and ergonomic API;</li> <li>this technique was popularized by <a href="#emotion">Emotion</a> v10;</li> <li>it's seems to be available only for React/JSX-based syntax</li> </ul> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">15. Framework agnostic</h4><a id="user-content-15-framework-agnostic" class="anchor" aria-label="Permalink: 15. Framework agnostic" href="#15-framework-agnostic"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Allows usage without, or with any framework. Some libraries are built specifically for React only.<br> <strong>NOTE</strong>: some libraries like <strong>Stitches</strong> or <strong>Emotion</strong> document only React usage, although they have a <strong>core</strong> that's framework agnostic.</p> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">16. Page size delta</h4><a id="user-content-16-page-size-delta" class="anchor" aria-label="Permalink: 16. Page size delta" href="#16-page-size-delta"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The total page size difference in kB (transferred gzipped & minified / uncompressed & minified) compared to <strong>CSS Modules</strong>, for the entire index page production build using Next.js:</p> <ul dir="auto"> <li>keep in mind that this includes an almost <strong>empty page</strong>, with only a couple of components;</li> <li>this is great for evaluating the minimal overhead, but does NOT offer any insight on the scaling factor: logarithmic, linear, or exponential;</li> </ul> <p dir="auto">NOTE: all builds were done with Next.js <code>11.1.0</code> and the values are taken from Chrome Devtools Network tab, <a href="https://developers.google.com/web/tools/chrome-devtools/network/reference#uncompressed" rel="nofollow">Transferred over network vs Resource size</a>.</p> <p dir="auto"><a href="#overview">⬆️ to overview</a></p> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Overall observations</h3><a id="user-content-overall-observations" class="anchor" aria-label="Permalink: Overall observations" href="#overall-observations"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The following observations apply for all solutions (with minor pointed exceptions).</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ Code splitting</h4><a id="user-content--code-splitting" class="anchor" aria-label="Permalink: ✅ Code splitting" href="#-code-splitting"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Components used only in a specific route will only be bundled for that route. This is something that Next.js performs out-of-the-box.</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ Global styles</h4><a id="user-content--global-styles" class="anchor" aria-label="Permalink: ✅ Global styles" href="#-global-styles"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All solutions offer a way to define global styles, some with a dedicated API.</p> <ul dir="auto"> <li><strong>Compiled</strong> is the only library that doesn't have a dedicated API for global styles at the moment, but it is <a href="https://github.com/atlassian-labs/compiled/issues/62" data-hovercard-type="issue" data-hovercard-url="/atlassian-labs/compiled/issues/62/hovercard">planned</a></li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ SSR</h4><a id="user-content--ssr" class="anchor" aria-label="Permalink: ✅ SSR" href="#-ssr"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All solutions offer Server-Side Rendering support and are easy to integrate with Next.js.</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ Vendor prefixes</h4><a id="user-content--vendor-prefixes" class="anchor" aria-label="Permalink: ✅ Vendor prefixes" href="#-vendor-prefixes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All solutions automatically add vendor specific prefixes out-of-the-box.</p> <ul dir="auto"> <li><strong>vanilla-extract</strong> is the only library that requires <a href="https://github.com/seek-oss/vanilla-extract/blob/master/docs/treat-migration-guide.md#autoprefixer-is-no-longer-included">manual setup</a></li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ Unique class names</h4><a id="user-content--unique-class-names" class="anchor" aria-label="Permalink: ✅ Unique class names" href="#-unique-class-names"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All solutions generate unique class names, like CSS Modules do. The algorithm used to generate these names varies a lot between libraries:</p> <ul dir="auto"> <li>some libraries use a <strong>hashing</strong> algorithm, requiring more computing, but resulting in idempotent names (for example: <code>.heading</code> style from <code>Card</code> component will always have the <code>.Card_heading_h7Ys5</code> hash);</li> <li>other libraries use <strong>counting</strong>, basically incrementing either a number (<code>.heading-0-2-1</code>, <code>.input-0-2-2</code>), or the alphabet letters (<code>a, b, c, ... aa, ab, ac</code>, etc), making this approach more performant, but resulting in non-idempotent class names (can't figure out if this has any potential drawbacks or not);</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ No inline styles</h4><a id="user-content--no-inline-styles" class="anchor" aria-label="Permalink: ✅ No inline styles" href="#-no-inline-styles"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">None of the solutions generate inline styles, which is an older approach, used by Radium & Glamor. The approach is <a href="https://esbench.com/bench/5908f78199634800a0347e94" rel="nofollow">less performant than CSS classes</a>, and it's <a href="https://reactjs.org/docs/dom-elements.html#style" rel="nofollow">not recommended</a> as a primary method for defining styles. It also implies using JS event handlers to trigger pseudo classes, as inline styles do not support them. Apparently, all modern solutions nowadays moved away from this approach.</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ Full CSS support</h4><a id="user-content--full-css-support" class="anchor" aria-label="Permalink: ✅ Full CSS support" href="#-full-css-support"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All solutions support most CSS properties that you would need: <strong>pseudo classes & elements</strong>, <strong>media queries</strong> and <strong>keyframes</strong> are the ones that we've tested.</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">✅ Critical CSS extraction</h4><a id="user-content--critical-css-extraction" class="anchor" aria-label="Permalink: ✅ Critical CSS extraction" href="#-critical-css-extraction"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Most solutions market themselves as being able to <em><strong>"extract critical CSS"</strong></em> during SSR. Please note that this does <strong>NOT refer</strong> to <a href="https://web.dev/extract-critical-css/" rel="nofollow">above-the-fold critical CSS extraction</a>, as we initially thought.</p> <p dir="auto">What they actually do:</p> <ul dir="auto"> <li>during SSR, they only generate styles for the <strong>visible</strong> elements of the static rendered page;</li> <li>they don't inject CSS for elements that are dynamically rendered, or lazy loaded;</li> </ul> <p dir="auto">With 100% static CSS, there would be actually no benefit. With dynamic pages that render very few elements on the server, and most components are rendered dynamically on the client, the benefit increases.</p> <p dir="auto"><strong>EXCEPTION</strong>: libraries that use <a href="#9-css-static-css-extraction">static CSS extraction</a>.</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">🟠 Performance Metrics</h4><a id="user-content--performance-metrics" class="anchor" aria-label="Permalink: 🟠 Performance Metrics" href="#-performance-metrics"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Understanding how these features affect <a href="https://web.dev/vitals/#core-web-vitals" rel="nofollow">Core Web Vitals</a> and <a href="https://web.dev/lighthouse-performance/#metrics" rel="nofollow">Performance Metrics</a> in general is an extremely important factor to consider, and the way styles are delivered to the client has probably the biggest impact, so let's analyse this in detail.</p> <p dir="auto">Also, there are 2 different scenarios we need to consider:</p> <ul dir="auto"> <li>📭 <strong>Empty cache</strong>: the user visits our page for the first time, or a returning user visits our page after the cache was invalidated (a new version was released);</li> <li>📬 <strong>Full cache</strong>: a returning user visits our page, and has all static resources cached (<code>.js</code>, <code>.css</code>, media, etc);</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">1. <code>.css</code> file extraction</h4><a id="user-content-1-css-file-extraction" class="anchor" aria-label="Permalink: 1. .css file extraction" href="#1-css-file-extraction"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Solutions that generate <code>.css</code> static files, which you normally would include as <code><link></code> tag(s) in the <code><head></code> of your page, are basically <a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css" rel="nofollow">rendering-blocking resources</a>. This highly affects <strong>FCP</strong>, <strong>LCP</strong> and any other metric that follows.</p> <p dir="auto">📭 <strong>Empty cache</strong><br> If the user has an empty cache, the following needs to happen, <strong>negatively</strong> impacting <strong>FCP</strong> and <strong>LCP</strong>:</p> <ul dir="auto"> <li>the browser needs to make an additional request, which implies a full <strong>RTT</strong> (Round Trip Time) to our server;</li> <li>transfer all CSS file content;</li> <li>parse it and build the CSSOM;</li> <li>these will delay any rendering of the <code><body></code>, even if the entire HTML is already loaded, and it may even be eagerly parsed, and some resources already fetched in advance;</li> </ul> <p dir="auto">It's true that you can fetch in <strong>parallel</strong> other <code><head></code> resources (additional <code>.css</code> or <code>.js</code> files), but this is generally a bad practice;</p> <p dir="auto">📬 <strong>Full cache</strong><br> However, on subsequent visits, the entire <code>.css</code> resource would be cached, so <strong>FCP</strong> and <strong>LCP</strong> would be positively impacted.</p> <br> <p dir="auto">💡 <strong>Key points</strong><br> This solution appears to be better suited when:</p> <ul dir="auto"> <li>we have many Server Side Rendered pages that our users visit, maybe even containing a common <code>.css</code> file that can be cached when visiting other pages;</li> <li>we don't update the styles frequently, so they can be cached for longer periods of time;</li> <li>we want to optimize for returning visitors, affecting first-time visits instead;</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">2. <code><style></code> tag injected styles</h4><a id="user-content-2-style-tag-injected-styles" class="anchor" aria-label="Permalink: 2. <style> tag injected styles" href="#2-style-tag-injected-styles"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">During <strong>SSR</strong>, styles will be added as <code><style></code> tag(s) in the <code><head></code> of the page. Keep in mind that these usually do NOT include all styles needed for the page, because most libraries perform <a href="#-critical-css-extraction">Critical CSS extraction</a>, so these <code>styles</code> should be usually smaller than the entire <code>.css</code> static file discussed previously.</p> <p dir="auto">📭 <strong>Empty cache</strong><br> Because we're shipping less CSS bytes, and they are inlined inside the <code>.html</code> file, this would result in faster <strong>FCP</strong> and <strong>LCP</strong>:</p> <ul dir="auto"> <li>we don't need additional requests for <code>.css</code> files, so the browser is not blocked;</li> <li>if we move all other <code>.js</code> files requests to the end of the document, <code><head></code> won't do any requests, so rendering will occur super fast;</li> <li>however, eventually we would ship additional bytes, that were not needed with static <code>.css</code> extraction: <ul dir="auto"> <li>the runtime library (between 1.6kB - 20kB);</li> <li>the styles required for the page, bundled in <code>.js</code> files along with the components, during <a href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web#rehydration-issues" rel="nofollow">hydration</a> (this includes all the critical CSS already shipped inside the <code><style></code> tag + others);</li> </ul> </li> <li>all these files are required to be fetched, parsed and executed to get a <strong>fully interactive</strong> page;</li> </ul> <p dir="auto">📬 <strong>Full cache</strong><br> When the user's cache is full, the additional <code>.js</code> files won't require fetching, as they are already cached.<br> However, if the page is <strong>SSRed</strong>, the inlined critical CSS rendered in the <code><style></code> tag of the document will be downloaded again, unless we deal with static HTML that can be cached as well, or we deal with HTML caching on our infrastructure.</p> <p dir="auto">But, by default, we will ship extra bytes on every page HTTP request, regardless if it's cached or not.</p> <br> <p dir="auto">💡 <strong>Key points</strong><br> This solution appears to be better suited when:</p> <ul dir="auto"> <li>we deal with SPA (Single Page Applications), where we have one (or few) SSR pages;</li> <li>we update the styles frequently, so even if they could be cached, it won't have a positive impact;</li> <li>we want to optimize for first-time visitors, affecting returning visitors instead;</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">🟠 Dead code removal</h4><a id="user-content--dead-code-removal" class="anchor" aria-label="Permalink: 🟠 Dead code removal" href="#-dead-code-removal"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Most solutions say they <em>remove unused code/styles</em>. This is only <strong>half-true</strong>.</p> <p dir="auto">Unused code is indeed more difficult to accumulate, especially if you compare it to plain <code>.css</code> files as we used to write <em>a decade ago</em>. But when compared to CSS Modules, the differencies are not that big. Any solution that offers the option to define <strong>arbitrary selectors</strong> or <strong>nested styles</strong> will bundle them, regardless if they are used or not inside our component. We've managed to ship unused SSR styles with all the tested solutions.</p> <p dir="auto">True & full unused code removal is difficult to implement, as the CSS syntax is not type-checked, nor statically analyzable. Also, the dynamic nature of components make it practically impossible in certain scenarios, especially when the markup is dynamically rendered:</p> <ul dir="auto"> <li><code>& span</code>: descendant elements;</li> <li><code>&:nth-child()</code>: certain pseudo selectors;</li> <li><code>& .bg-${color}</code>: dynamic selectors;</li> <li><code>.parent &</code>: parent selectors;</li> </ul> <p dir="auto">Basically, what we get is code removal when we delete the component, or we don't import it anymore. That's implicit behaviour, because the styles are a direct dependency of the component. When the component is gone, so are its styles.</p> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">🟠 Debugging / Inspecting</h4><a id="user-content--debugging--inspecting" class="anchor" aria-label="Permalink: 🟠 Debugging / Inspecting" href="#-debugging--inspecting"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">There are 2 methods to inject CSS into the DOM & update it from JavaScript:</p> <br> <div class="markdown-heading" dir="auto"><h5 tabindex="-1" class="heading-element" dir="auto">1. Using <code><style></code> tag(s)</h5><a id="user-content-1-using-style-tags" class="anchor" aria-label="Permalink: 1. Using <style> tag(s)" href="#1-using-style-tags"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This approach implies adding one or more <code><style></code> tag(s) in the DOM (either in the <code><head></code> or somewhere in the <code><body></code>), using <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild" rel="nofollow">.appendChild()</a> to add the <code><style></code> Node(s), in addition with either <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent" rel="nofollow">.textContent</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML" rel="nofollow">.innerHTML</a> to update the <code><style></code> tag(s).</p> <ul dir="auto"> <li>using this approach, we can easily <em>see</em> what styles get added to the DOM, because we can inspect the DOM from our DevTools, like any other DOM Node;</li> <li>using only one <code><style></code> tag and updating its whole content, could be slow to update the entire DOM when we actually changed only a tiny set of CSS rule(s);</li> <li>most libraries use this solution in <code>DEVELOPMENT</code> mode, because it provides a better debugging experience; <ul dir="auto"> <li><strong>TypeStyle</strong> uses this in <code>PRODUCTION</code> also;</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h5 tabindex="-1" class="heading-element" dir="auto">2. Using <code>CSSStyleSheet</code> API</h5><a id="user-content-2-using-cssstylesheet-api" class="anchor" aria-label="Permalink: 2. Using CSSStyleSheet API" href="#2-using-cssstylesheet-api"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">First used by <strong>JSS</strong>, this method uses <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule" rel="nofollow"><code>CSSStyleSheet.insertRule()</code></a> to inject CSS rules directly into the <strong>CSSOM</strong>.</p> <ul dir="auto"> <li>using this approach it's a bit more difficult to <em>see</em> what styles get injected into the CSSOM, because even if you see the CSS applied on the elements (thanks to <a href="https://developer.chrome.com/blog/css-in-js/" rel="nofollow">CSS-in-JS support in Chrome</a>) it will point to an empty <code><style></code> tag; <ul dir="auto"> <li>to see all the injected styles, you'll have to select the <code><style></code> tag;</li> <li>get access to it via <code>$0</code> in Chrome DevTools (or get a reference to it in any other way, using the DOM API);</li> <li>access <code>.sheet.cssRules</code> on the <code><style></code> tag to see the Array of CSS rules that it contains;</li> </ul> </li> <li>this method is apparently more performant than the previous one, during dynamic styles update, so most libraries use this method in <code>PRODUCTION</code>; <ul dir="auto"> <li>performance gains apply only when adding new CSS rules, or updating existing ones (ie: dynamic styles update at runtime);</li> <li><strong>JSS</strong> and <strong>Stitches</strong> use it in <code>DEVELOPMENT</code> mode as well;</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">❌ No component deduping</h4><a id="user-content--no-component-deduping" class="anchor" aria-label="Permalink: ❌ No component deduping" href="#-no-component-deduping"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If the same component is imported by 2 different routes, it will be send twice to the client. This is surely a limitation of the bundler/build system, in our case Next.js, and <strong>not related to the CSS-in-JS solution</strong>.</p> <p dir="auto">In Next.js, code-splitting works at the route level, bundling all components required for a specific route, but according to their <a href="https://nextjs.org/blog/next-9-2#improved-code-splitting-strategy" rel="nofollow">official blog</a> and <a href="https://web.dev/granular-chunking-nextjs/" rel="nofollow">web.dev</a> if a component is used in <strong>more than 50%</strong> of the pages, it should be included in the <code>commons</code> bundle. However, in our example, we have 2 pages, each of them importing the <code>Button</code> component, and it's included in each page bundle, not in the <code>commons</code> bundle. Since the code required for styling is bundled with the component, this limitation will impact the styles as well, so it's worth keeping this in mind.</p> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">CSS Modules</h3><a id="user-content-css-modules" class="anchor" aria-label="Permalink: CSS Modules" href="#css-modules"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This is a well established, mature and solid approach. Without a doubt, it's a great improvement over BEM, SMACCS, OOCSS, or any other scalable CSS methodology to structure and organize our CSS, especially in component-based applications.</p> <p dir="auto">Launched in <strong>2015</strong> | <a href="#overview">Back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">❌ <strong>No Styles/Component co-location</strong></p> </li> <li> <p dir="auto">❌ <strong>No TypeScript support</strong></p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto">❌ <strong>No Theming support</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ plain CSS</li> <li>❌ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>❌ Contextual styles: <em>(requires SASS, LESS or Stylus)</em></li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>❌ <code>styled</code> component</li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>✅ <code>.css</code> file extraction</li> <li>❌ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <p dir="auto">This is the baseline we'll consider when comparing all the following <strong>CSS-in-JS</strong> solutions. Checkout the <a href="#motivation">motivation</a> to better understand the limitations of this approach that we're trying to fill.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">76.7 kB</td> <td align="right">233 kB</td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.19 kB 68.7 kB ├ └ css/1d1f8eb014b85b65feee.css 450 B ├ /_app 0 B 66.5 kB ├ ○ /404 194 B 66.7 kB └ ○ /other 744 B 67.2 kB └ css/1c8bc5a96764df6b92b4.css 481 B + First Load JS shared by all 66.5 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.40892d.js 555 B ├ chunks/webpack.ddd010.js 822 B └ css/a92bf2d3acbab964f6ac.css 319 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.19 kB 68.7 kB ├ └ css/1d1f8eb014b85b65feee.css 450 B ├ /_app 0 B 66.5 kB ├ ○ /404 194 B 66.7 kB └ ○ /other 744 B 67.2 kB └ css/1c8bc5a96764df6b92b4.css 481 B + First Load JS shared by all 66.5 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.40892d.js 555 B ├ chunks/webpack.ddd010.js 822 B └ css/a92bf2d3acbab964f6ac.css 319 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Styled JSX</h3><a id="user-content-styled-jsx" class="anchor" aria-label="Permalink: Styled JSX" href="#styled-jsx"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Very simple solution, doesn't have a dedicated website for documentation, everything is on Github. It's not popular, but it is the built-in solution in Next.js.</p> <p dir="auto">Version: <strong><code>4.0</code></strong> | Maintained by <a href="https://github.com/vercel">Vercel</a> | Launched in <strong>2017</strong> | <a href="https://github.com/vercel/styled-jsx">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">🟠 <strong>Context-aware code completion</strong>: to get syntax highlighting & code completion, an editor extension is required</p> </li> <li> <p dir="auto">🟠 <strong>TypeScript support</strong>: <code>@types</code> can be additionaly installed, but the API is too minimal to require TS</p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto">❌ <strong>No Theming support</strong></p> </li> <li> <p dir="auto">❌ <strong>Not Framework agnostic</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ Tagged Templates</li> <li>❌ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>❌ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>❌ <code>styled</code> component</li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😌 out-of-the-box support with Next.js</li> <li>👍 for user input styles, it generates a new class name for each change, but it removes the old one</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😏 unlike CSS modules, we can target HTML <code>elements</code> also, and it generates unique class names for them (not sure if it's a good practice, though)</li> <li>🤓 we'll need to optimize our styles by <a href="https://github.com/vercel/styled-jsx#dynamic-styles">splitting static & dynamic styles</a>, to avoid rendering duplicated styles</li> <li>🤨 unique class names are added to elements, even if we don't target them in our style definition, resulting in un-needed slight html pollution (optimizing this is cumbersome, and it's <em>a lot of work for little benefit</em>)</li> <li>😕 it will bundle any defined styles, regardless if they are used or not, just like plain CSS</li> <li>😢 there's no support for <strong>contextual styles</strong>, so defining <strong>pseudo classes</strong> or <strong>media queries</strong> has the same downsides as plain CSS, requiring selectors/class names duplication (a <a href="https://github.com/vercel/styled-jsx#css-preprocessing-via-plugins">SASS plugin</a> is required to get this feature)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Overall, we felt like writting plain CSS, with the added benefit of being able to define the styles along with the component, so we <strong>don't need an additional <code>.css</code> file</strong>. Indeed, this is the philosophy of the library: supporting CSS syntax inside the component file. We can <strong>use any JS/TS constants of functions</strong> with string interpolation. Working with <strong>dynamic styles is pretty easy</strong> because it's plain JavaScript in the end. We get all these benefits at a very low price, with a pretty <strong>small bundle overhead</strong>.</p> <p dir="auto">The downsides are the overall experience of writting plain CSS. <strong>Without nesting support</strong> pseudo classes/elements and media queries getting pretty cumbersome to manage.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">79.5 kB</td> <td align="right">245 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+2.8 kB</strong></td> <td align="right"><strong>+12 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.65 kB 72.6 kB ├ /_app 0 B 70 kB ├ ○ /404 194 B 70.2 kB └ ○ /other 1.18 kB 71.2 kB + First Load JS shared by all 70 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.a4b061.js 4.12 kB └ chunks/webpack.61f1b6.js 778 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.65 kB 72.6 kB ├ /_app 0 B 70 kB ├ ○ /404 194 B 70.2 kB └ ○ /other 1.18 kB 71.2 kB + First Load JS shared by all 70 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.a4b061.js 4.12 kB └ chunks/webpack.61f1b6.js 778 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Styled Components</h3><a id="user-content-styled-components" class="anchor" aria-label="Permalink: Styled Components" href="#styled-components"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">For sure one of the most popular and mature solutions, with good documentation. It uses Tagged Templates to defines styles by default, but can use objects as well. It also popularized the <code>styled</code> components approach, which creates a new component along with the defined styles.</p> <p dir="auto">Version: <strong><code>5.3</code></strong> | Maintained by <a href="https://twitter.com/mxstbr" rel="nofollow">Max Stoiber</a> & <a href="https://opencollective.com/styled-components#category-ABOUT" rel="nofollow">others</a> | Launched in <strong>2016</strong> | <a href="https://styled-components.com/docs" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong>: <code>@types</code> must be additionaly installed, via DefinitelyTyped</p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">🟠 <strong>Context-aware code completion</strong>: requires an editor extension/plugin</p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>❌ <code>className</code></li> <li>✅ <code>styled</code> component</li> <li>✅ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-1" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-1"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>🤓 we need to split static & dynamic styles, otherwise it will render duplicate output</li> <li>😕 bundles nested styles even if they are not used in component</li> <li>😵 we can mix Tagged Templates with Styled Objects, which could lead to convoluted and different syntax for each approach (kebab vs camel, EOL character, quotes, interpolation, etc)</li> <li>🥴 some more complex syntax appears to be a bit cumbersome to get right (mixing animations with Styled Objects, dynamic styles based on <code>Props</code> variations, etc)</li> <li>🤫 for user input styles, it generates a new class name for each update, but it does NOT remove the old ones, appending indefinitely to the DOM</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-1" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-1"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Styled components offers a novel approach to styling components using the <code>styled</code> method which creates a new component including the defined styles. We don't feel like writting CSS, so coming from CSS Modules we'll have to learn a new, more programatic way, to define styles. Because it allows both <code>string</code> and <code>object</code> syntax, it's a pretty flexibile solution both for migrating our existing styles, and for starting a project from scratch. Also, the maintainers did a pretty good job keeping up with most of the innovations in this field.</p> <p dir="auto">However before adopting it, we must be aware that it comes with a certain cost for our bundle size.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">90.1 kB</td> <td align="right">272 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+13.4 kB</strong></td> <td align="right"><strong>+39 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.52 kB 83.1 kB ├ /_app 0 B 80.6 kB ├ ○ /404 194 B 80.8 kB └ ○ /other 1.06 kB 81.7 kB + First Load JS shared by all 80.6 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.731ace.js 14.7 kB └ chunks/webpack.ddd010.js 822 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.52 kB 83.1 kB ├ /_app 0 B 80.6 kB ├ ○ /404 194 B 80.8 kB └ ○ /other 1.06 kB 81.7 kB + First Load JS shared by all 80.6 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.731ace.js 14.7 kB └ chunks/webpack.ddd010.js 822 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Emotion</h3><a id="user-content-emotion" class="anchor" aria-label="Permalink: Emotion" href="#emotion"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Probably the most comprehensive, complete and sofisticated solution. Detailed documentation, fully built with TypeScript, looks very mature, rich in features and well maintained.</p> <p dir="auto">Version: <strong><code>11.4</code></strong> | Maintained by <a href="https://twitter.com/mitchellhamiltn" rel="nofollow">Mitchell Hamilton</a> & <a href="https://opencollective.com/emotion#category-ABOUT" rel="nofollow">others</a> | Launched in <strong>2017</strong> | <a href="https://emotion.sh/docs/introduction" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong>: for using the <code>styled</code> components approach, an additional editor plugin is required</p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code> <em>(using <a href="https://emotion.sh/docs/@emotion/css" rel="nofollow">@emotion/css</a>)</em></li> <li>✅ <code>styled</code> component</li> <li>✅ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-1" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-1"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😎 the <code>css</code> prop offers great ergonomics during development, however it seems to be a newer approach, based on <a href="https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html" rel="nofollow">React 17 new <code>jsx</code> transform</a>, and <a href="https://emotion.sh/docs/css-prop" rel="nofollow">configuring</a> it is not trivial, differs on your setup, and implies some boilerplate (which should change soon and become easier)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-2" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-2"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>🤫 for user input styles, it generates a new class name for each update, but it does NOT remove the old ones, appending indefinitely to the DOM</li> <li>😑 using <code>styled</code> approach will add <code>3 kB</code> to our bundle, because it's imported from a separate package</li> <li>🤔 don't know how to split static and dynamic styles, resulting in highly polluted duplicated styles for component variants, specifically problematic for SSR (same applies to <code>css</code> prop & <code>styled</code> components)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-2" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-2"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Overall Emotion looks to be a very solid and flexible approach. The novel <code>css</code> prop approach offers great ergonomics for developers. Working with dynamic styles and TypeScript is pretty easy and intuitive. Supporting both <code>strings</code> and <code>objects</code> when defining styles, it can be easily used both when migrating from plain CSS, or starting from scratch. The bundle overhead is not negligible, but definitely much smaller than other solutions, especially if you consider the rich set of features that it offers.</p> <p dir="auto">It seems it doesn't have a dedicated focus on performance, but more on Developer eXperience. It looks like a perfect "well-rounded" solution.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">83.2 kB</td> <td align="right">253 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+6.5 kB</strong></td> <td align="right"><strong>+20 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.5 kB 76.4 kB ├ /_app 0 B 73.9 kB ├ ○ /404 194 B 74.1 kB └ ○ /other 1.07 kB 74.9 kB + First Load JS shared by all 73.9 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.6cb893.js 23.3 kB ├ chunks/pages/_app.b6d380.js 7.68 kB └ chunks/webpack.ddd010.js 822 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.5 kB 76.4 kB ├ /_app 0 B 73.9 kB ├ ○ /404 194 B 74.1 kB └ ○ /other 1.07 kB 74.9 kB + First Load JS shared by all 73.9 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.6cb893.js 23.3 kB ├ chunks/pages/_app.b6d380.js 7.68 kB └ chunks/webpack.ddd010.js 822 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">TypeStyle</h3><a id="user-content-typestyle" class="anchor" aria-label="Permalink: TypeStyle" href="#typestyle"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Minimal library, focused only on type-checking. It is framework agnostic, that's why it doesn't have a special API for handling dynamic styles. There are React wrappers available, but the typings feels a bit convoluted.</p> <p dir="auto">Version: <strong><code>2.1</code></strong> | Maintained by <a href="https://twitter.com/basarat" rel="nofollow">Basarat</a> | Launched in <strong>2017</strong> | <a href="https://typestyle.github.io/" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">🟠 <strong>Built-in Theming support</strong>: uses TS <code>namespaces</code> to define theming, which is <a href="https://basarat.gitbook.io/typescript/project/namespaces" rel="nofollow">not a recommended TS feature</a> even by the author himself, or by TS core team member <a href="https://youtu.be/8qm49TyMUPI?t=1277" rel="nofollow">Orta Therox</a>.</p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>❌ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>❌ <code>styled</code> component</li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-3" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-3"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>😕 it doesn't handle dynamic styles, so we have to use regular JS functions to compute styles</li> <li>🤨 when composing styles, we'll have to manually add some internal typings</li> <li>🤔 don't know how to split dynamic and static styles, so it's very easy to create duplicated generated code with dynamic styles, specifically problematic with SSR</li> <li>😱 it creates a single <code><style></code> tag with all the styles, and replaces it on update, and apparently it doesn't use <code>insertRule()</code>, not even in production builds, which might be an important performance drawback in large & highly dynamic UIs</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-3" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-3"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Overall TypeStyle seems a minimal library, relatively easy to adopt because we don't have to rewrite our components, thanks to the classic <code>className</code> approach. However we do have to rewrite our styles, because of the Style Object syntax. We didn't feel like writting CSS, so there is a learning curve we need to climb.</p> <p dir="auto">With Next.js or React in general we don't get much value out-of-the-box, so we still need to perform a lot of manual work. The external <a href="https://github.com/Malpaux/react-typestyle">react-typestyle</a> binding doesn't support hooks, it seems to be an abandoned project and the typings are too convoluted to be considered an elegant solution.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">78.8 kB</td> <td align="right">241 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+2.1 kB</strong></td> <td align="right"><strong>+8 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.44 kB 72.1 kB ├ /_app 0 B 69.7 kB ├ ○ /404 194 B 69.9 kB └ ○ /other 975 B 70.7 kB + First Load JS shared by all 69.7 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.5b0422.js 3.81 kB └ chunks/webpack.61f1b6.js 778 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.44 kB 72.1 kB ├ /_app 0 B 69.7 kB ├ ○ /404 194 B 69.9 kB └ ○ /other 975 B 70.7 kB + First Load JS shared by all 69.7 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.5b0422.js 3.81 kB └ chunks/webpack.61f1b6.js 778 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Fela</h3><a id="user-content-fela" class="anchor" aria-label="Permalink: Fela" href="#fela"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">It appears to be a mature solution, with quite a number of users. The API is intuitive and very easy to use, great integration for React using hooks.</p> <p dir="auto">Version: <strong><code>11.6</code></strong> | Maintained by <a href="https://twitter.com/robinweser" rel="nofollow">Robin Weser</a> | Launched in <strong>2016</strong> | <a href="https://fela.js.org/docs/" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>Atomic CSS</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">🟠 <strong>TypeScript support</strong>: it exposes Flow types, which work ok, from our (limited) experience</p> </li> <li> <p dir="auto">🟠 <strong>Context-aware code completion</strong>: styles defined outside the component require <a href="https://github.com/andreipfeiffer/css-in-js/blob/fela/components/input.tsx#L29">explicit typing</a> to get code completion</p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>🟠 Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>❌ <code>styled</code> component</li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-2" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-2"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😌 easy and simple to use API, very intuitive</li> <li>🥳 creates very short and atomic class names (like <code>a</code>, <code>b</code>, ...)</li> <li>😎 it has a lot of plugins that can add many additional features (but will also increase bundle size)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-4" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-4"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>🤨 when defining styles outside the component, we have to explicitly add some internal typings to get code completion</li> <li>🥺 there's no actual TS support and the maintainer considers it a <a href="https://github.com/robinweser/fela/issues/590#issuecomment-409373362" data-hovercard-type="issue" data-hovercard-url="/robinweser/fela/issues/590/hovercard">low priority</a></li> <li>🤕 without TS support, we cannot get fully type-safe integration into Next.js + TS (there are <a href="https://twitter.com/pfeiffer_andrei/status/1349106486740475904" rel="nofollow">missing types from the definition file</a>)</li> <li>🤔 the docs say it supports string based styles, but they are a second-class citizen and they seem to work only for global styles</li> <li>😵 some information in the docs is spread on various pages, sometimes hard to find without a search feature, and the examples and use cases are not comprehensive</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-4" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-4"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Fela looks to be a mature solution, with active development. It introduces 2 great features which we enjoyed a lot. The first one is the basic principle that <em>"Style as a Function of State"</em> which makes working with dynamic styles feel super natural and integrates perfectly with React's mindset. The second is atomic CSS class names, which should potentially scale great when used in large applications.</p> <p dir="auto">The lack of TS support however is a bummer, considering we're looking for a fully type-safe solution. Also, the scaling benefits of atomic CSS should be measured against the library bundle size.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">88.6 kB</td> <td align="right">276 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+11.9 kB</strong></td> <td align="right"><strong>+43 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.84 kB 81.7 kB ├ /_app 0 B 78.9 kB ├ ○ /404 194 B 79 kB └ ○ /other 1.43 kB 80.3 kB + First Load JS shared by all 78.9 kB ├ chunks/framework.2191d1.js 42.4 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.32bc1d.js 12.6 kB └ chunks/webpack.ddd010.js 822 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.84 kB 81.7 kB ├ /_app 0 B 78.9 kB ├ ○ /404 194 B 79 kB └ ○ /other 1.43 kB 80.3 kB + First Load JS shared by all 78.9 kB ├ chunks/framework.2191d1.js 42.4 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.32bc1d.js 12.6 kB └ chunks/webpack.ddd010.js 822 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Stitches</h3><a id="user-content-stitches" class="anchor" aria-label="Permalink: Stitches" href="#stitches"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Very young library, solid, modern and well-thought-out solution. The overall experience is just great, full TS support, a lot of other useful features baked in the lib.</p> <p dir="auto">Version: <strong><code>0.2.5 (beta)</code></strong> | Maintained by <a href="https://github.com/modulz">Modulz</a> | Launched in <strong>2020</strong> | <a href="https://stitches.dev/docs" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong>: <em>(available with <code>@stitches/core</code>)</em></p> </li> <li> <p dir="auto">❌ <strong>Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>❌ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>✅ <code>styled</code> component</li> <li>🟠 <code>css</code> prop <em>(used only to override <code>styled</code> components)</em></li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-3" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-3"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😌 easy and simple to use API, a pleasure to work with</li> <li>😎 great design tokens management and usage</li> <li>🥰 documentation is exactly what we'd expect: no more, no less</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-5" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-5"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>🤔 dynamic styles can be defined either using built-in <code>variants</code> (for predefined styles), or styles created inside the component to get access to the <code>props</code></li> <li>🧐 would help a lot to get the search feature inside the docs</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-5" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-5"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Stitches is probably the most modern solution to this date, with full out-of-the-box support for TS. Without a doubt, they took some of the best features from other solutions and put them together for an awesome development experience. The first thing that impressed us was definitely the documentation. The second, is the API they expose which is close to top-notch. The features they provide are not huge in quantity, but are very well-thought-out.</p> <p dir="auto">However, we cannot ignore the fact that it's still in beta. Also, the authors identify it as <em>"near-zero runtime"</em>, but at <strong>+9 kB gzipped</strong> it's debatable.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">82.0 kB</td> <td align="right">250 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+5.3 kB</strong></td> <td align="right"><strong>+17 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.43 kB 75.2 kB ├ /_app 0 B 72.8 kB ├ ○ /404 194 B 73 kB └ ○ /other 984 B 73.8 kB + First Load JS shared by all 72.8 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.ff82f0.js 6.93 kB └ chunks/webpack.61f1b6.js 778 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.43 kB 75.2 kB ├ /_app 0 B 72.8 kB ├ ○ /404 194 B 73 kB └ ○ /other 984 B 73.8 kB + First Load JS shared by all 72.8 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.ff82f0.js 6.93 kB └ chunks/webpack.61f1b6.js 778 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">JSS</h3><a id="user-content-jss" class="anchor" aria-label="Permalink: JSS" href="#jss"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Probably the grandaddy around here, JSS is a very mature solution being the first of them, and still being maintained. The API is intuitive and very easy to use, great integration for React using hooks.</p> <p dir="auto">Version: <strong><code>10.7</code></strong> | Maintained by <a href="https://twitter.com/oleg008" rel="nofollow">Oleg Isonen</a> and <a href="https://opencollective.com/jss#category-ABOUT" rel="nofollow">others</a> | Launched in <strong>2014</strong> | <a href="https://cssinjs.org/" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>🟠 Tagged Templates: <em>(available with additional <a href="https://cssinjs.org/jss-plugin-template" rel="nofollow">plugin</a>, with limited features)</em></li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>🟠 <code>styled</code> component <em>(available with additional <a href="https://cssinjs.org/styled-jss" rel="nofollow">plugin</a>)</em></li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-4" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-4"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😌 easy and simple to use API, very intuitive</li> <li>😎 it has a lot of plugins that can add many additional features (but will also increase bundle size)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-6" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-6"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>😳 keep in mind that <a href="https://github.com/cssinjs/jss/blob/master/packages/react-jss/package.json#L47"><code>react-jss</code> package</a>, which is used with React/Next.js, depends on <a href="https://cssinjs.org/jss-preset-default" rel="nofollow">jss-preset-default</a>, which includes many <a href="https://github.com/cssinjs/jss/blob/master/packages/jss-preset-default/package.json#L35-L47">plugins</a> by default, so you don't need to manually add some of the plugins;</li> <li>🤔 <code>react-jss</code> uses className by default. There's also <code>styled-jss</code> that uses <strong>Styled Components</strong> approach, but it has no types, and couldn't make it work on top of <code>react-jss</code>;</li> <li>😤 global styles were frustrating to setup, we've finally managed to used them thanks to <a href="https://stackoverflow.com/questions/54201412/how-can-i-add-style-to-the-body-element-with-jss" rel="nofollow">StackOverFlow</a>, because the docs have no mention of <code>injectSheet</code> API (or we couldn't find it anywhere);</li> <li>😖 the docs are generally difficult to follow, and finding the information you need is a cumbersome process: <ul dir="auto"> <li>there is no search;</li> <li>there are a lot of plugins, so you don't know where to look for a particular feature;</li> <li>some plugins influence other plugins, or other docs pages, and they sometimes don't contain all the combinations of features, so the docs are not comprehensive (ie: we had to figure out on our own how to use <strong>contextual styles</strong> with <strong>media queries</strong>).</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-6" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-6"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The API is similar in many ways to React Native StyleSheets, while the hooks helper allows for easy dynamic styles definition. There are many plugins that can add a lot of features to the core functionality, but attention must be payed to the total bundle size, which is significant even with the bare minimum only.</p> <p dir="auto">Also, being the first CSS-in-JS solution built, it lacks many of the modern features that focuses on developer experience.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">94.9 kB</td> <td align="right">293 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+18.2 kB</strong></td> <td align="right"><strong>+60 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.45 kB 88 kB ├ /_app 0 B 85.6 kB ├ ○ /404 194 B 85.8 kB └ ○ /other 992 B 86.6 kB + First Load JS shared by all 85.6 kB ├ chunks/framework.2191d1.js 42.4 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.5f0007.js 19.2 kB └ chunks/webpack.9c89cc.js 956 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.45 kB 88 kB ├ /_app 0 B 85.6 kB ├ ○ /404 194 B 85.8 kB └ ○ /other 992 B 86.6 kB + First Load JS shared by all 85.6 kB ├ chunks/framework.2191d1.js 42.4 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.5f0007.js 19.2 kB └ chunks/webpack.9c89cc.js 956 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Goober</h3><a id="user-content-goober" class="anchor" aria-label="Permalink: Goober" href="#goober"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A very light-weight solution, with a loads of features.</p> <p dir="auto">Version: <strong><code>2.0</code></strong> | Maintained by <a href="https://twitter.com/cristianbote_" rel="nofollow">Cristian Bote</a> | Launched in <strong>2019</strong> | <a href="https://goober.js.org/" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>✅ <code>styled</code> component (<em>see details below</em>)</li> <li>🟠 <code>css</code> prop (<em>is supported, but requires a separate babel plugin</em>)</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction</li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-5" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-5"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>🤏 really tiny</li> <li>😎 it supports a very wide range of defining styles, so it's pretty versatile and full featured in this regard (however, I fear that having all these options, a large team could mix various ways of defining styles, so it's more difficult to <em>enforce consistency</em>)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-7" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-7"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>🤫 for user input styles, it generates a new class name for each update, but it does NOT remove the old ones, appending indefinitely to the DOM</li> <li>🤔 don't know how to split static and dynamic styles, resulting in highly polluted duplicated styles for component variants, specifically problematic for SSR</li> <li>😱 it creates a single <code><style></code> tag with all the styles, and appends to it on update, and apparently it doesn't use <code>insertRule()</code>, not even in production builds, which might be an important performance drawback in large & highly dynamic UIs</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-7" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-7"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Looking at Goober you cannot ask yourself what kind of magic did Cristian Bote do to fit all the features inside this tiny library. It is really mind blowing. It is marketed as being <em>"less than 1KB"</em>, which is not entirely accurate, but still... it's the smallest library we've tested.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">77.8 kB</td> <td align="right">237 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+1.1 kB</strong></td> <td align="right"><strong>+4 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.77 kB 71.1 kB ├ /_app 0 B 68.3 kB ├ ○ /404 194 B 68.5 kB └ ○ /other 2.39 kB 70.7 kB + First Load JS shared by all 68.3 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.5ee014.js 2.42 kB └ chunks/webpack.61f1b6.js 778 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.77 kB 71.1 kB ├ /_app 0 B 68.3 kB ├ ○ /404 194 B 68.5 kB └ ○ /other 2.39 kB 70.7 kB + First Load JS shared by all 68.3 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.5ee014.js 2.42 kB └ chunks/webpack.61f1b6.js 778 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Compiled</h3><a id="user-content-compiled" class="anchor" aria-label="Permalink: Compiled" href="#compiled"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A rather new library, having the huge Atlassian platform supporting and probably using it. Many existing features, even more in development, or planned for development.</p> <p dir="auto">Version: <strong><code>0.6</code></strong> | Maintained by <a href="https://github.com/atlassian-labs">Atlassian</a> | Launched in <strong>2020</strong> | <a href="https://compiledcssinjs.com/docs/" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Atomic CSS</strong></p> </li> <li> <p dir="auto">❌ <strong>Not Framework agnostic</strong></p> </li> <li> <p dir="auto">❌ <strong>No Built-in Theming support</strong> <em>(at least at the moment, but it is <a href="https://github.com/atlassian-labs/compiled/issues/18" data-hovercard-type="issue" data-hovercard-url="/atlassian-labs/compiled/issues/18/hovercard">planned</a>)</em></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Arbitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>🟠 <code>className</code> <em>(only supported with a custom <a href="https://compiledcssinjs.com/docs/class-names" rel="nofollow">ClassNames</a> component)</em></li> <li>✅ <code>styled</code> component</li> <li>✅ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>❌ <code>.css</code> file extraction <em>(currently under development, will be shipped in 2021)</em></li> <li>✅ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-6" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-6"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😌 using the <code>css</code> prop is seamless and trivial, not requiring any special setup (unlike Emotion)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-8" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-8"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>🧐 styles are not placed in the <code><head></code> during SSR - instead they are placed right before the element using them in the <code><body></code>, which could potentially provide slightly faster Paint metrics, such as FCP, or LCP, because the browser can start rendering the body faster and incrementally, not waiting for the entire block of styles to be parsed</li> <li>😕 bundles nested styles even if they are not used in component</li> <li>😔 currently has no API for global styles, but it is <a href="https://github.com/atlassian-labs/compiled/issues/62" data-hovercard-type="issue" data-hovercard-url="/atlassian-labs/compiled/issues/62/hovercard">planned</a> to be added</li> <li>😳 <code>ClassNames</code> API, which enables us to apply styles as class name strings, is a bit convoluted and weird at first sight.</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-8" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-8"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Compiled is a very promising library. Considering that it offers both atomic CSS, and it plans to support static <code>.css</code> extraction, with excellent TypeScript support and style co-location, it would be quite unique (having only <a href="#style9">style9</a> as a direct competitor).</p> <p dir="auto">Also, we cannot ignore that is has Atlassian supporting its development, which puts a (slightly) bigger weight on the confidence level.</p> <p dir="auto">The total bundle overhead is pretty small, the runtime library being quite light-weight. With static <code>.css</code> file extraction, this could potentially become even smaller.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">80.2 kB</td> <td align="right">242 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+3.5 kB</strong></td> <td align="right"><strong>+9 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.11 kB 71.8 kB ├ /_app 0 B 66.5 kB ├ ○ /404 194 B 66.7 kB └ ○ /other 888 B 70.6 kB + First Load JS shared by all 66.5 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.ebe095.js 576 B ├ chunks/webpack.ddd010.js 822 B └ css/a92bf2d3acbab964f6ac.css 319 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.11 kB 71.8 kB ├ /_app 0 B 66.5 kB ├ ○ /404 194 B 66.7 kB └ ○ /other 888 B 70.6 kB + First Load JS shared by all 66.5 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.ebe095.js 576 B ├ chunks/webpack.ddd010.js 822 B └ css/a92bf2d3acbab964f6ac.css 319 B </code></pre></div> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Linaria</h3><a id="user-content-linaria" class="anchor" aria-label="Permalink: Linaria" href="#linaria"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Linaria is all about static CSS extraction and avoiding any runtime overhead.</p> <p dir="auto">Version: <strong><code>3.0 (beta)</code></strong> | Maintained by <a href="https://github.com/callstack">Callstack</a> | Launched in <strong>2018</strong> | <a href="https://github.com/callstack/linaria#documentation">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>Styles/Component co-location</strong></p> </li> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">❌ <strong>No Atomic CSS</strong></p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>✅ Tagged Templates</li> <li>❌ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>✅ Arbitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>✅ <code>styled</code> component</li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>✅ <code>.css</code> file extraction</li> <li>❌ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-7" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-7"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😎 it's the only existing library at the moment (with a stable release) that supports both co-location & static CSS extraction (Compiled could also support this soon)</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-9" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-9"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😕 bundles nested styles even if they are not used in component</li> <li>😔 <a href="https://github.com/callstack/linaria/blob/master/docs/BASICS.md#adding-global-styles">global styling</a> is documented, but we didn't get to make them work with Next.js</li> <li>😳 documentation is not top-notch, there isn't a dedicated website, no search feature and it feels like trial & error when trying to find a piece of information</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-9" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-9"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Linaria is highly inspired from Astroturf, combining various features from other libraries.</p> <p dir="auto">Version 3 is currently in Beta, not sure what the changelog is compared to v2. It's still in development by the <em>React/Native geeks</em> at <strong>Callstack.io</strong>, but we couldn't find which of the big players use it in production.</p> <p dir="auto">It seems to have a slightly larger overall page size (<code>2.9 KB</code>), but we didn't investigate where does this come from. Also, there's an open question if this overhead is fixed or if it scales.</p> <p dir="auto">PS: thanks to <a href="https://github.com/daniepetrov">Daniil Petrov</a> for his PR with the Next.js integration</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">79.4 kB</td> <td align="right">239 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+2.7 kB</strong></td> <td align="right"><strong>+6 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 4.99 kB 71.5 kB ├ └ css/16f3e95ede28dcc048f2.css 423 B ├ /_app 0 B 66.5 kB ├ ○ /404 194 B 66.7 kB └ ○ /other 3.59 kB 70.1 kB └ css/3064299bff08067ec7dd.css 427 B + First Load JS shared by all 66.5 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.98e8c3.js 598 B ├ chunks/webpack.ddd010.js 822 B └ css/7739287c04a618ea0c54.css 295 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 4.99 kB 71.5 kB ├ └ css/16f3e95ede28dcc048f2.css 423 B ├ /_app 0 B 66.5 kB ├ ○ /404 194 B 66.7 kB └ ○ /other 3.59 kB 70.1 kB └ css/3064299bff08067ec7dd.css 427 B + First Load JS shared by all 66.5 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.b2b078.js 23.1 kB ├ chunks/pages/_app.98e8c3.js 598 B ├ chunks/webpack.ddd010.js 822 B └ css/7739287c04a618ea0c54.css 295 B </code></pre></div> <br> <hr> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">vanilla-extract</h3><a id="user-content-vanilla-extract" class="anchor" aria-label="Permalink: vanilla-extract" href="#vanilla-extract"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Modern solution with great TypeScript integration and no runtime overhead. It's pretty minimal in its features, straightforward and opinionated. Everything is processed at compile time, and it generates static CSS files. Successor of <a href="#treat">Treat</a>, also be called "Treat v3", is developed and maintained by the same authors.</p> <p dir="auto">Version: <strong><code>1.2</code></strong> | Maintained by <a href="https://github.com/seek-oss/">Seek OSS</a> | Launched in <strong>2021</strong> | <a href="https://vanilla-extract.style/" rel="nofollow">View Docs</a> | ... <a href="#overview">back to Overview</a></p> <br> <ul dir="auto"> <li> <p dir="auto">✅ <strong>TypeScript support</strong></p> </li> <li> <p dir="auto">✅ <strong>Built-in Theming support</strong></p> </li> <li> <p dir="auto">✅ <strong>Context-aware code completion</strong></p> </li> <li> <p dir="auto">✅ <strong>Framework agnostic</strong></p> </li> <li> <p dir="auto">🟠 <strong>Atomic CSS</strong>: can be achieved with <a href="https://www.npmjs.com/package/@vanilla-extract/sprinkles" rel="nofollow">Sprinkles</a></p> </li> <li> <p dir="auto">❌ <strong>No Styles/Component co-location</strong>: styles must be placed in an external <code>.css.ts</code> file</p> </li> <li> <p dir="auto"><strong>Styles definition method(s)</strong></p> <ul dir="auto"> <li>❌ Tagged Templates</li> <li>✅ Style Objects</li> </ul> </li> <li> <p dir="auto"><strong>Styles nesting</strong></p> <ul dir="auto"> <li>✅ Contextual styles</li> <li>❌ Abitrary nesting</li> </ul> </li> <li> <p dir="auto"><strong>Styles apply method(s)</strong></p> <ul dir="auto"> <li>✅ <code>className</code></li> <li>❌ <code>styled</code> component</li> <li>❌ <code>css</code> prop</li> </ul> </li> <li> <p dir="auto"><strong>Styles output</strong></p> <ul dir="auto"> <li>✅ <code>.css</code> file extraction</li> <li>❌ <code><style></code> tag injection</li> </ul> </li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Other benefits</h4><a id="user-content-other-benefits-8" class="anchor" aria-label="Permalink: Other benefits" href="#other-benefits-8"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>👮 forbids <strong>nested arbitrary selectors</strong> (ie: <code>& > span</code>), which might be seen as a downside, but it actually discourages bad-practices like <strong>specificity wars</strong>, which should be avoided when scaling CSS (however, this is impossible to be statically type-checked without <em>pattern matching</em>, so it will throw a runtime exception)</li> <li>🥳 generates the same filename hash on build, if styles haven't changes, meaning that end-users benefit of CSS cache-ing even when deploying new versions with component updates only (logic, or content), without styles updates</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Worth mentioning observations</h4><a id="user-content-worth-mentioning-observations-10" class="anchor" aria-label="Permalink: Worth mentioning observations" href="#worth-mentioning-observations-10"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>😌 in contrast with Treat, it relies on CSS Variables support, which means: 1) it doesn't work on IE, 2) is simpler and easier to maintain, 3) it supports other bundlers besides webpack</li> <li>😕 bundles all styles, exported or not, even if they are not used in component</li> <li>😥 it doesn't handle dynamic styles: you can use built-in <code>variants</code> based on predefined types, or <strong>inline styles</strong> for user-defined styles</li> </ul> <br> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Conclusions</h4><a id="user-content-conclusions-10" class="anchor" aria-label="Permalink: Conclusions" href="#conclusions-10"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">We felt a lot like using CSS Modules: we need an external file for styles, we place the styles on the elements using <code>className</code>, we handle dynamic styles with <strong>inline styles</strong>, etc. However, we don't write CSS, and the overall experience with TypeScript support is magnificent, because everything is typed, so we don't do any <strong>copy-paste</strong>. Error messages are very helpful in guiding us when we do something we're not supposed to do.</p> <p dir="auto">vanilla-extract is built with restrictions in mind, with a strong user-centric focus, balacing the developer experience with solid TypeScript support. It's also worth mentioning that <a href="https://twitter.com/markdalgleish" rel="nofollow">Mark Dalgleish</a>, co-author of CSS Modules, works at Seek and he's also a contributor.</p> <p dir="auto">The authors vision is to think of vanilla-extract as a low-level utility for building higher-level frameworks, which will probably happen in the future.</p> <br> <markdown-accessiblity-table><table> <thead> <tr> <th align="left"></th> <th align="right">Transferred / gzipped</th> <th align="right">Uncompressed</th> </tr> </thead> <tbody> <tr> <td align="left">Index page size</td> <td align="right">76.7 kB</td> <td align="right">231 kB</td> </tr> <tr> <td align="left">vs. CSS Modules</td> <td align="right"><strong>+0.0 kB</strong></td> <td align="right"><strong>-2 kB</strong></td> </tr> </tbody> </table></markdown-accessiblity-table> <br> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Page Size First Load JS ┌ ○ / 2.09 kB 68.5 kB ├ └ css/37c023369f5e1762e423.css 370 B ├ /_app 0 B 66.4 kB ├ ○ /404 194 B 66.6 kB └ ○ /other 611 B 67 kB └ css/a56b9d05c6da35ff125f.css 386 B + First Load JS shared by all 66.4 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.700159.js 23.1 kB ├ chunks/pages/_app.bfd136.js 565 B ├ chunks/webpack.61f1b6.js 778 B └ css/23b89d9ef0ca05e4b917.css 286 B"><pre class="notranslate"><code>Page Size First Load JS ┌ ○ / 2.09 kB 68.5 kB ├ └ css/37c023369f5e1762e423.css 370 B ├ /_app 0 B 66.4 kB ├ ○ /404 194 B 66.6 kB └ ○ /other 611 B 67 kB └ css/a56b9d05c6da35ff125f.css 386 B + First Load JS shared by all 66.4 kB ├ chunks/framework.895f06.js 42 kB ├ chunks/main.700159.js 23.1 kB ├ chunks/pages/_app.bfd136.js 565 B ├ chunks/webpack.61f1b6.js 778 B └ css/23b89d9ef0ca05e4b917.css 286 B </code></pre></div> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Libraries not included</h2><a id="user-content-libraries-not-included" class="anchor" aria-label="Permalink: Libraries not included" href="#libraries-not-included"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">We know there are a lot of other libraries out there, besides the ones covered above. We're only covered the ones that have support for <strong>React</strong>, support for <strong>SSR</strong>, an easy integration with <strong>Next.js</strong>, good <strong>documentation</strong> and a sense of ongoing <strong>support and maintenance</strong>. Please checkout our <a href="#goals">goals</a>.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Treat</h3><a id="user-content-treat" class="anchor" aria-label="Permalink: Treat" href="#treat"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://seek-oss.github.io/treat/" rel="nofollow">Treat</a> was initially included in the analysis with v1.6, but removed for a few reasons:</p> <ol dir="auto"> <li>the library itself is replaced by <a href="#vanilla-extract">vanilla-extract</a></li> <li>Next.js integration is not supported with v2</li> <li>we couldn't upgrade to Next.js v11/webpack 5 even with v1</li> </ol> <p dir="auto">The main difference between vanilla-extract and Treat is that the latter supports IE and legacy browsers as well.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">style9</h3><a id="user-content-style9" class="anchor" aria-label="Permalink: style9" href="#style9"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://github.com/johanholmerin/style9">Style9</a> is a new library, inspired by Facebook's own CSS-in-JS solution called stylex. Style9 is unique because it's the only open source library that supports both <code>.css</code> static extraction + atomic CSS, and/or styles co-location. It has TS support and easy to integrate with Next.js.</p> <p dir="auto">However, it has quite a few limitations (at least as of Feb 2021) that makes it practically unusable in a real production application that we would want to scale, both in code & team size:</p> <ul dir="auto"> <li>cannot use design tokens defined as <code>Enum</code> or <code>POJO</code>, only constant primitives are supported, which is a <strong>big deal breaker</strong>;</li> <li>dynamic styles are not trivial: <ul dir="auto"> <li>it supports styles toggling, similar to <code>classNames</code> lib, but not dynamically/computed/expression based;</li> <li>for user styles, so we have to use inline styles;</li> <li>there is an experimental addon <a href="https://github.com/johanholmerin/style9-components.macro">style9-components</a> that tries to solve this;</li> </ul> </li> <li>no global styles support;</li> <li>no theming support (not a deal breaker for us): <ul dir="auto"> <li>there is some exploration in this regard, with <a href="https://github.com/johanholmerin/style9-theme.macro">style9-theme</a>;</li> </ul> </li> <li>documentation is not comprehensive, it contains a lot of code comments, without code examples, making it even more difficult to follow & understand</li> </ul> <p dir="auto">Some upsides:</p> <ul dir="auto"> <li>it's the first lib we've tested that actually doesn't bundle unused styles;</li> <li>it doesn't allow arbitrary seletors / nesting, which is a good thing, because it enforces good practices and consistency;</li> <li>it is framework agnostic;</li> </ul> <p dir="auto">As a conclusion, it wants to be a powerful solution with very interesting and unique set of features, but it's not mature yet. As far as we see, it's currently mostly designed towards more static solutions. Dynamic styling seems to be difficult to handle, at least for the moment.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Tailwind</h3><a id="user-content-tailwind" class="anchor" aria-label="Permalink: Tailwind" href="#tailwind"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Not an actual CSS-in-JS library, more like a replacement for traditional CSS styling. It uses atomic CSS classes (some of them having multiple properties) that we attach to html elements. We don't write CSS, instead we use a different DSL to specify styles, pseudo classes, media queries, etc.</p> <p dir="auto">The reason we didn't include it in our thorough review is because it doesn't fully meet our <a href="#goals">goals</a>:</p> <ul dir="auto"> <li>it doesn't provide TS support, or type-safety <ul dir="auto"> <li>we cannot use out own design tokens from <code>.ts</code> files to include them in <code>tailwind.config</code> (cannot <code>import</code> any file, cannot require <code>.ts</code>)</li> <li>using <code>tailwind.config</code> directly offers no type-safety when importing it, or using <a href="https://tailwindcss.com/docs/configuration#referencing-in-java-script" rel="nofollow"><code>resolveConfig</code></a></li> <li>there is a <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/pull/50921" data-hovercard-type="pull_request" data-hovercard-url="/DefinitelyTyped/DefinitelyTyped/pull/50921/hovercard">PR on Definitely Typed</a>, but we're not sure if it will support the custom config, as well</li> <li>there might be workarounds, but these are just proofs that there isn't a clean way to achieve this</li> </ul> </li> <li>dynamic styles have some limitations: we have to be aware of <a href="https://tailwindcss.com/docs/optimizing-for-production#writing-purgeable-html" rel="nofollow">purging</a> to not get missing design tokens in production builds</li> <li>we have to learn a new DSL: some style are similar and easy to deduce from their CSS counterparts, others are pretty different, and we have to learn (<code>rounded</code>, <code>place-self/content</code>, <code>divide</code>, <code>ring</code>)</li> <li>some advanced CSS features, like <a href="https://github.com/tailwindlabs/tailwindcss/discussions/2119" data-hovercard-type="discussion" data-hovercard-url="/tailwindlabs/tailwindcss/discussions/2119/hovercard"><code>::after</code> pseudo elements</a> are tricky</li> <li>there are libraries like <a href="https://github.com/Arthie/xwind">xwind</a> which integrates Tailwind with CSS-in-JS solutions, which is supports our theory that Tawilwind is not a replacement for CSS-in-JS, not does it address the same problems</li> </ul> <p dir="auto">Some upsides:</p> <ul dir="auto"> <li>we don't write CSS, which is indeed difficult to master</li> <li>the entire team uses the same "styling system"</li> <li>a shitton of predefined design tokens, plus the ability to customize them</li> <li>successfully bundles only used styles, doesn't bundle all classes defined in <code>tailwind.config</code> <ul dir="auto"> <li>exception: keyframe animations (spin, ping, etc)</li> <li>beware of purging</li> </ul> </li> </ul> <p dir="auto">Tailwind seems to be more than a <em>styling tool</em>, it also offers some out-of-the-box utils + a ready-made design system that you can use right away.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Aphrodite</h3><a id="user-content-aphrodite" class="anchor" aria-label="Permalink: Aphrodite" href="#aphrodite"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">It's not a popular solution, the approach is similar to <strong>React Native StyleSheets</strong> way of styling components. Has built-in TypeScript support and a simple API.</p> <ul dir="auto"> <li>global styles are a bit cumbersome to define</li> <li>able to nest media queries & pseudo selectors, but cannot nest arbitrary rules/selectors</li> <li>no dynamic out-of-the-box support, so we have to get around that, like inline styles I guess, or like in React Native</li> <li>doesn't add any real value, except the ergonomics to colocate styles with the component.</li> </ul> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Glamor</h3><a id="user-content-glamor" class="anchor" aria-label="Permalink: Glamor" href="#glamor"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">I got it started with Next.js, but it feels fragile. The <a href="https://github.com/vercel/next.js/tree/canary/examples/with-glamor">Glamor official example</a> throws an error regarding <code>rehydrate</code>. When commenting it out, it works, but not sure what the consequences are.</p> <ul dir="auto"> <li>it looks like an unmaintained or abandoned package</li> <li>documentation is pretty minimal</li> <li>lacks any TS support</li> <li>has a lot of documented experimental features, marked as "buggy"</li> <li>it feels like a side/internal project at FB, that is not used anymore.</li> </ul> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Cxs</h3><a id="user-content-cxs" class="anchor" aria-label="Permalink: Cxs" href="#cxs"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Didn't manage to start it with Next.js + TypeScript. The <a href="https://github.com/vercel/next.js/tree/canary/examples/with-cxs">official example</a> uses version 3, while today we have version 6. The example doesn't work, because the API has changed.</p> <p dir="auto">The solution looked interesting, because it is supposed to be very light-weight.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Astroturf</h3><a id="user-content-astroturf" class="anchor" aria-label="Permalink: Astroturf" href="#astroturf"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Didn't manage to start it with Next.js + TypeScript. There was an <a href="https://github.com/vercel/next.js/tree/canary/examples/with-astroturf">official example</a> that used an older version of Next.js, but the example if not there anymore.</p> <p dir="auto">The solution is not that popular, but it was the first to use <code>.css</code> extraction with collocated styles.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Otion</h3><a id="user-content-otion" class="anchor" aria-label="Permalink: Otion" href="#otion"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Looks promising, atomic css and light-weight. It has a working <a href="https://github.com/kripod/otion/tree/main/packages/example-nextjs">Next.js example</a>, but we didn't consider it because it lacks any documentation.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Styletron</h3><a id="user-content-styletron" class="anchor" aria-label="Permalink: Styletron" href="#styletron"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">It looks like a not so popular solution, which also lacks support for TypeScript. It looks like the maintainers work at Uber and they use it internally. It focused on generating unique atomic CSS classes, which could potentially deduplicate a lot of code.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Radium</h3><a id="user-content-radium" class="anchor" aria-label="Permalink: Radium" href="#radium"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The project was put in <a href="https://formidable.com/blog/2019/radium-maintenance/" rel="nofollow">Maintenance Mode</a>. They recommend other solutions.</p> <br> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Glamorous</h3><a id="user-content-glamorous" class="anchor" aria-label="Permalink: Glamorous" href="#glamorous"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The project was <a href="https://github.com/paypal/glamorous/issues/419" data-hovercard-type="issue" data-hovercard-url="/paypal/glamorous/issues/419/hovercard">discontinued</a> in favor of Emotion.</p> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Running the examples</h2><a id="user-content-running-the-examples" class="anchor" aria-label="Permalink: Running the examples" href="#running-the-examples"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Each implementation sits on their own branch, so we can have a clear separation at built time.</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# install dependencies yarn # for development yarn dev # for production yarn build yarn start"><pre><span class="pl-c"><span class="pl-c">#</span> install dependencies</span> yarn <span class="pl-c"><span class="pl-c">#</span> for development</span> yarn dev <span class="pl-c"><span class="pl-c">#</span> for production</span> yarn build yarn start</pre></div> <br> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Feedback and Suggestions</h2><a id="user-content-feedback-and-suggestions" class="anchor" aria-label="Permalink: Feedback and Suggestions" href="#feedback-and-suggestions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To get in touch, my DMs are open <a href="https://twitter.com/pfeiffer_andrei" rel="nofollow">@pfeiffer_andrei</a>.</p> <br> <p dir="auto"><strong>Special thanks and appreciations</strong> go to everyone that helped putting this document together, and making it more accurate:</p> <ul dir="auto"> <li>Martin Hochel (<a href="https://twitter.com/martin_hotell" rel="nofollow">@martin_hotell</a>)</li> <li>Oleg Isonen (<a href="https://twitter.com/oleg008" rel="nofollow">@oleg008</a>)</li> </ul> </article></div></div></div></div></div> <!-- --> <!-- --> <script type="application/json" id="__PRIMER_DATA_:R0:__">{"resolvedServerColorMode":"day"}</script></div> </react-partial> <input type="hidden" data-csrf="true" value="Yo3fn5tQzyQglR8UaOdc50I/Iapc24yK70uTLn9oSE04HxWmGC0aIlxmqQp0sqSYh6O2TjygbkxwGJpdQi9sLQ==" /> </div> <div data-view-component="true" class="Layout-sidebar"> <div class="BorderGrid about-margin" data-pjax> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <div class="hide-sm hide-md"> <h2 class="mb-3 h4">About</h2> <p class="f4 my-3"> A thorough analysis of all the current CSS-in-JS solutions with SSR & TypeScript support for Next.js </p> <h3 class="sr-only">Topics</h3> <div class="my-3"> <div class="f6"> <a href="/topics/typescript" title="Topic: typescript" data-view-component="true" class="topic-tag topic-tag-link"> typescript </a> <a href="/topics/reactjs" title="Topic: reactjs" data-view-component="true" class="topic-tag topic-tag-link"> reactjs </a> <a href="/topics/nextjs" title="Topic: nextjs" data-view-component="true" class="topic-tag topic-tag-link"> nextjs </a> <a href="/topics/styling" title="Topic: styling" data-view-component="true" class="topic-tag topic-tag-link"> styling </a> <a href="/topics/css-in-js" title="Topic: css-in-js" data-view-component="true" class="topic-tag topic-tag-link"> css-in-js </a> <a href="/topics/comparison" title="Topic: comparison" data-view-component="true" class="topic-tag topic-tag-link"> comparison </a> </div> </div> <h3 class="sr-only">Resources</h3> <div class="mt-2"> <a class="Link--muted" data-analytics-event="{"category":"Repository Overview","action":"click","label":"location:sidebar;file:readme"}" href="#readme-ov-file"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book mr-2"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> Readme </a> </div> <include-fragment src="/andreipfeiffer/css-in-js/hovercards/citation/sidebar_partial?tree_name=main"> </include-fragment> <div class="mt-2"> <a href="/andreipfeiffer/css-in-js/activity" data-view-component="true" class="Link Link--muted"><svg text="gray" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pulse mr-2"> <path d="M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z"></path> </svg> <span class="color-fg-muted">Activity</span></a> </div> <h3 class="sr-only">Stars</h3> <div class="mt-2"> <a href="/andreipfeiffer/css-in-js/stargazers" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> <strong>846</strong> stars</a> </div> <h3 class="sr-only">Watchers</h3> <div class="mt-2"> <a href="/andreipfeiffer/css-in-js/watchers" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-eye mr-2"> <path d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"></path> </svg> <strong>16</strong> watching</a> </div> <h3 class="sr-only">Forks</h3> <div class="mt-2"> <a href="/andreipfeiffer/css-in-js/forks" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <strong>23</strong> forks</a> </div> <div class="mt-2"> <a class="Link--muted" href="/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fandreipfeiffer%2Fcss-in-js&report=andreipfeiffer+%28user%29"> Report repository </a> </div> </div> </div> </div> <div class="BorderGrid-row" hidden> <div class="BorderGrid-cell"> <include-fragment src="/andreipfeiffer/css-in-js/used_by_list" accept="text/fragment+html"> </include-fragment> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3"> <a href="/andreipfeiffer/css-in-js/graphs/contributors" data-view-component="true" class="Link--primary no-underline Link d-flex flex-items-center">Contributors <span title="4" data-view-component="true" class="Counter ml-1">4</span></a></h2> <include-fragment src="/andreipfeiffer/css-in-js/contributors_list?count=4&current_repository=css-in-js&items_to_show=4" aria-busy="true" aria-label="Loading contributors"> <ul class="list-style-none "> <li class="mb-2 d-flex"> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> <div class="Skeleton Skeleton--text flex-1 flex-self-center f4"> </div> </li> <li class="mb-2 d-flex"> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> <div class="Skeleton Skeleton--text flex-1 flex-self-center f4"> </div> </li> <li class="mb-2 d-flex"> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> <div class="Skeleton Skeleton--text flex-1 flex-self-center f4"> </div> </li> <li class="mb-2 d-flex"> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> <div class="Skeleton Skeleton--text flex-1 flex-self-center f4"> </div> </li> </ul> </include-fragment> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3">Languages</h2> <div class="mb-2"> <span data-view-component="true" class="Progress"> <span style="background-color:#3178c6 !important;;width: 56.1%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#663399 !important;;width: 43.9%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> </span></div> <ul class="list-style-none"> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/andreipfeiffer/css-in-js/search?l=typescript" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#3178c6;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">TypeScript</span> <span>56.1%</span> </a> </li> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/andreipfeiffer/css-in-js/search?l=css" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#663399;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">CSS</span> <span>43.9%</span> </a> </li> </ul> </div> </div> </div> </div> </div></div> </div> </div> </turbo-frame> </main> </div> </div> <footer class="footer pt-8 pb-6 f6 color-fg-muted p-responsive" role="contentinfo" > <h2 class='sr-only'>Footer</h2> <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap"> <div class="d-flex flex-items-center flex-shrink-0 mx-2"> <a aria-label="Homepage" title="GitHub" class="footer-octicon mr-2" href="https://github.com"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path> </svg> </a> <span> © 2025 GitHub, Inc. </span> </div> <nav aria-label="Footer"> <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3> <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading"> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to Terms","label":"text:terms"}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to privacy","label":"text:privacy"}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to security","label":"text:security"}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to status","label":"text:status"}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to docs","label":"text:docs"}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to contact","label":"text:contact"}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a> </li> <li class="mx-2" > <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{"location":"footer","action":"cookies","context":"subfooter","tag":"link","label":"cookies_link_subfooter_footer"}" > Manage cookies </button> </cookie-consent-link> </li> <li class="mx-2"> <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{"location":"footer","action":"dont_share_info","context":"subfooter","tag":"link","label":"dont_share_info_link_subfooter_footer"}" > Do not share my personal information </button> </cookie-consent-link> </li> </ul> </nav> </div> </footer> <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999" data-initial-cookie-consent-allowed="" data-cookie-consent-required="false"></ghcc-consent> <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> You can’t perform that action at this time. </div> <template id="site-details-dialog"> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open> <summary role="button" aria-label="Close dialog"></summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal"> <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div class="octocat-spinner my-6 js-details-dialog-spinner"></div> </details-dialog> </details> </template> <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;"> <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;"> </div> </div> <template id="snippet-clipboard-copy-button"> <div class="zeroclipboard-container position-absolute right-0 top-0"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> <template id="snippet-clipboard-copy-button-unpositioned"> <div class="zeroclipboard-container"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> </div> <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div> <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div> </body> </html>