{"id":16660050,"url":"https://github.com/dvingo/cljs-styled-components","last_synced_at":"2025-07-21T21:31:46.450Z","repository":{"id":44986908,"uuid":"141048758","full_name":"dvingo/cljs-styled-components","owner":"dvingo","description":"ClojureScript wrapper for styled-components","archived":false,"fork":false,"pushed_at":"2023-01-09T16:29:27.000Z","size":362,"stargazers_count":52,"open_issues_count":5,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-14T22:38:02.806Z","etag":null,"topics":["clojurescript","styled-components"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dvingo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-15T18:21:51.000Z","updated_at":"2025-03-19T14:59:09.000Z","dependencies_parsed_at":"2023-02-08T13:00:43.488Z","dependency_job_id":null,"html_url":"https://github.com/dvingo/cljs-styled-components","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/dvingo/cljs-styled-components","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvingo%2Fcljs-styled-components","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvingo%2Fcljs-styled-components/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvingo%2Fcljs-styled-components/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvingo%2Fcljs-styled-components/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dvingo","download_url":"https://codeload.github.com/dvingo/cljs-styled-components/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvingo%2Fcljs-styled-components/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266382214,"owners_count":23920665,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojurescript","styled-components"],"created_at":"2024-10-12T10:27:40.106Z","updated_at":"2025-07-21T21:31:46.415Z","avatar_url":"https://github.com/dvingo.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cljs-styled-components\n\n\n---\n\n_note_ \n\nI made a similar library to this one built on top of emotion instead of styled-components.\n\nhttps://github.com/dvingo/cljs-emotion\n\nEmotion allows passing functions as children when defining styles and has built-in server-side rendering support.\n\n---\n\n\nA ClojureScript interface to the [styled-components](https://www.styled-components.com) library.\n\nThe main interface of styled-components' template strings is replaced by\nClojureScript maps.\n\nIt's mostly a lightweight transformation from ClojureScript maps to the form\nthat a template literal gets invoked with.\n\n# Installation\n\nThis library will require \"styled-components\" from node_modules.\n\nYou can install it like so:\n\n```bash\nyarn add styled-components\n# or\nnpm i styled-components\n```\n\nThen specify this library as a dependency using lein, boot, deps:\n\n[![Clojars Project](https://img.shields.io/clojars/v/cljs-styled-components.svg)](https://clojars.org/cljs-styled-components)\n\n# Usage\n\nAdd the dependency to your namespace form:\n\n```clojure\n;; Plain React elements (e.g. used in fulcro):\n[cljs-styled-components.core :refer [defstyled defkeyframes theme-provider clj-props set-default-theme!]]\n\n;; For reagent support:\n[cljs-styled-components.reagent :refer [defstyled defkeyframes theme-provider clj-props set-default-theme!]]\n```\n\nHere is a very simple usage:\n\n```clojure\n(defstyled row-container\n  :div {:display \"flex\"})\n```\nWhich is functionally equivalent to the JS:\n\n```js\nconst RowContainer = styled.div`\n  display: flex;\n`\nconst rowContainer = (props, children) =\u003e React.createElement(RowContainer, props, children)\n```\n\nThe first argument is the Var name that will be created, the second argument\ncan be one of:\n  - a keyword will be invoked on the `styled` object\n\n    ```clojure\n    (defstyled example1 :p {:color \"blue\"})\n    ```\n  - a styled component - as constructed with `defstyled`\n\n    ```clojure\n    (defstyled example2 example1 {:border \"1px solid\"})\n    ```\n\n     https://www.styled-components.com/docs/basics#extending-styles\n  - any react component, which will invoke styled on the component\n\n    ```clojure\n    (defn my-component [props]\n      (dom/div {:className (goog.object/get props \"className\")}\n          (goog.object/get props \"children\")))\n\n    (defstyled example2 my-component {:border \"1px solid\"}).\n    ```\n\n    as described here:\n    https://www.styled-components.com/docs/advanced#styling-normal-react-components\n\nThe third argument must be a ClojureScript map or a ClojureScript vector, this is computed at runtime\nso you can construct this map/vector any way you like.\n\nA more featureful example:\n\n```clojure\n(defstyled number-cell-styled\n  :div\n  {:background-color\n                    (clj-props (fn [{:keys [selected? answered? answered-correctly? background-color]}]\n                                 (cond\n                                   background-color background-color\n                                   selected? \"darkGrey\"\n                                   (and answered? answered-correctly?) \"green\"\n                                   (and answered? (not answered-correctly?)) \"red\"\n                                   :else \"hsl(37, 67%, 99%)\")))\n   :font-family     \"patua\"\n   :color           #(goog.object/getValueByKeys % \"theme\" \"textColor\")\n   :padding         \"0\"\n   :height          cell-size-px\n   :width           cell-size-px\n   :min-width       cell-size-px\n   :font-size       (str (/ cell-size 2) \"px\")\n   :display         \"flex\"\n   :justify-content \"center\"\n   :align-items     \"center\"\n   \"@media (max-width: 700px)\"\n                    {:height    sm-cell-size-px\n                     :min-width sm-cell-size-px\n                     :width     sm-cell-size-px}})\n\n(set-default-theme! number-cell-styled #js {:textColor \"red\"})\n```\n\nNested selectors are supported as shown in this example with media queries.\n\n## Props\n\nAny property value that is a function will get passed the props that the component\nwas rendered with.\n\nThe props will be a JavaScript object, to make the code more cljs friendly the\nfollowing custom is used:\n\n```clojure\n;; At render time any data under the `:clj` key will remain as ClojureScript\n;; data structures.\n(example {:clj {:round? true}})\n\n;; Then pull them out with the helper `clj-props`\n(defstyled example :div\n           {:color         \"red\"\n            :border        \"1px solid blue\"\n            :border-radius (clj-props #(if (:round? %) \"10px\" \"0px\"))})\n```\n\nThe top level map will converted to a JS object with (clj-\u003ejs)\n(the `:clj` key is dissoc'ed first).\n\nExample using JS data structures:\n\n```clojure\n(defstyled example2 :div\n           {:color #(goog.object/get % \"color\")})\n\n;; render time:\n(example2 {:color \"blue\"})\n```\n\n## Theme support\n\nThis is essentially the unmodified theme code that styled-components uses,\nso everything must be in JS data.\n\n```clojure\n(defstyled theme-user :div\n           {:color #(goog.object/getValueByKeys % \"theme\" \"textColor\")})\n\n(def theme\n  #js {:textColor \"purple\"})\n\n;; fulcro\n  (theme-provider #js {:theme theme}\n    (dom/div\n      (theme-user \"hello\")))\n\n;; reagent\n[theme-provider #js {:theme theme}\n  [:div\n   [theme-user \"hello\"]]]\n```\n\n## Animations\n\nAs of Styled components [V4](https://www.styled-components.com/releases#v4.0.0):\n\n\u003e Keyframes is now implemented in a \"lazy\" manner: its styles will be injected with the render phase of components using them.\n\n\u003e keyframes no longer returns an animation name, instead it returns an object which has method .getName() for the purpose of getting the animation name.\n\nThe current strategy to deal with this change is to have `defkeyframes` return\na function that delegates to `css` for you. (see: https://www.styled-components.com/docs/basics#animations)\n\nAn example:\n\n```clojure\n(:require\n  [cljs-styled-components.core :refer [clj-props] :refer-macros [defstyled defkeyframes]])\n\n(defkeyframes\n  spin\n  \"from { transform: rotate(0deg);}\n   to { transform: rotate(360deg); }\")\n\n;; `spin` will be a function that delegates to the styled components css helper\n;; as described here:\n;; https://www.styled-components.com/docs/basics#animations\n(defstyled rotate-text :span\n           {:animation (spin \"2s linear infinite\")\n            :display \"inline-block\"\n            :font-size \"20px\"})\n\n;; Then just render like any component.\n(defn animation [txt]\n      (rotate-text txt))\n\n;; An example reading data from props:\n(defstyled rotate-text2\n  :span\n  {:animation (clj-props (fn [a] (spin (str (:time a) \"s linear infinite\"))))\n   :display   \"inline-block\"\n   :font-size \"20px\"})\n\n(defn animation2 [txt]\n      (rotate-text2  {:clj {:time 10}} txt))\n```\n\n## Style Mixins\n\n### CLJS Maps\n\nThe styles are just maps so you can use whatever code you want to combine them together:\n\n```clojure\n(def row\n  {:display \"flex\"\n   :justify-content \"space-between\"})\n\n(defstyled my-list :div\n  (merge\n    row\n    {:background \"blue\"}))\n ```\n\n### Vectors\nAs a convenience you can also pass a vector of maps which will be merged for you:\n\n```clojure\n(defstyled example-12 :div\n           [{:background \"red\"}\n            {:font-size \"20px\"}])\n```\n\nPassing JavaScript objects is also supported, as well as in nested positions:\n\n```clojure\n(defstyled example-11 :div\n [(position \"relative\" \"20px\")\n   {:background \"green\"\n    :opacity 1\n    \":hover\" [(transitions \"opacity 1s ease-in 0s\")\n              {:background \"blue\"\n               :opacity .5}]}])\n```\n\n### JS Objects\n\nThis library plays well with \"mixins\" such as [polished](https://github.com/styled-components/polished)\n\n```bash\nyarn add polished\n```\n\nSupport for nested objects of properties is included, for example, many of the\nmixins in polished (https://polished.js.org/docs/) have this shape:\n\n```js\nconst div = styled.div`\n  backgroundImage: url(logo.png);\n  ${hideText()};\n`\n```\n\nIn cljs we need a map to have an even number of forms so support for this is\nadded by putting the mixins under the keyword: `:styled/mixins`.\n\nHere's an example:\n\n```clojure\n(defstyled mixme :section\n           {:background-color \"lightblue\"\n            :opacity 1\n            :font-size (em \"16px\")\n            :styled/mixins\n                              [(position \"absolute\" \"-22px\" \"5px\" \"5px\" \"4px\")\n                               (transitions \"opacity 0.5s ease-in 0s\")\n                               (size \"40px\" \"300px\")\n                               (borderStyle \"solid\" \"dashed\" \"dotted\" \"double\")]\n            \":hover\"          {:opacity 0.5}})\n\n(defn mixins []\n      (dom/div {:style {:position \"relative\"}}\n               (mixme \" hi \")))\n\n```\nIf you only need one mixin, you can just include it and do not need to embed in\na vector:\n\n```clojure\n(defstyled :div\n  {:background-image: \"url(logo.png)\"\n   :sytled/mixins (hideText)})\n```\nThe library will merge JS objects and CLJS maps for you if you pass a vector like so:\n\n```clojure\n(defstyled my-component :div\n  [(position \"absolute\" \"-22px\" \"5px\" \"5px\" \"4px\")\n   {:color \"blue\"}])\n\n;;\n(defstyled sample :section\n  [(position \"absolute\" \"-22px\" \"5px\" \"5px\" \"4px\")\n   (transitions \"opacity 0.5s ease-in 0s\")\n   (size \"40px\" \"300px\")\n   (borderStyle \"solid\" \"dashed\" \"dotted\" \"double\")\n   {:background-color \"lightblue\"\n    :opacity          1\n    :font-size        (em \"16px\")\n    \":hover\"          {:opacity 0.5}}])\n```\n\nSo either of the these forms work for including style mixin objects.\n\n## Global styles\n\nYou can use the macro `defglobalstyle` which takes the same arguments as defstyled except for the \"type\" of element\nas there is none, and delegates to `createGlobalStyle` of styled-components.\n\nsee: https://styled-components.com/docs/api#createglobalstyle\n\nExample:\n\n```clojure\n;; require the macro:\n(:require [cljs-styled-components.core :refer-macros [defglobalstyle]])\n(:require [cljs-styled-components.reagent :refer-macros [defglobalstyle]])\n\n(defglobalstyle\n  my-global-styles\n  {\".my-global-class\" {:background \"palevioletred\"\n                       :border \"2px dashed\"\n                       :border-radius (clj-props #(if (:round %) \"8px\") \"0\")}})\n\n;; reagent\n(defn my-component []\n  [:div.my-global-class\n    [my-global-styles {:clj {:round true}}]\n    \"This inserts global styles\"])\n\n;; fulcro\n(dom/div {:className \"my-global-class\"}\n    (my-global-styles)\n    \"This inserts global styles\")\n```\n\n## Props macro helper\n\nYou can use the `sprops` macro to clean up accessing props.\n\n```clojure\n[cljs-styled-components.core :refer-macros [defstyled sprops]]\n;; or:\n[cljs-styled-components.reagent :refer-macros [defstyled sprops]]\n\n(defstyled use-props-macro :div\n  {:border-radius (sprops [round?] (if round? \"4px\" 0))})\n;; expands to:\n(defstyled use-props-macro :div\n  {:border-radius (clj-props (fn [{:keys [round?]}] (if round? \"4px\" 0)))})\n\n(dom/div {:clj {:round? true}} \"use props\")\nor\n[:div {:clj {:round? true}} \"use props\"]\n```\n\n# Implementation notes\n\n\nIn JS:\n\n```js\nconst aVar = 'good';\n\n// These are equivalent:\nfn`this is a ${aVar} day`;\nfn([ 'this is a ', ' day' ], aVar);\n```\n\nSo you could use styled components from ClojureScript directly by using the second\nform, but this library is an experiment in making it a bit nicer to work with\nfrom ClojureScript.\n\nYou can read more about template literals here:\n\nhttps://www.styled-components.com/docs/advanced#tagged-template-literals\n\nand here:\n\nhttps://mxstbr.blog/2016/11/styled-components-magic-explained/\n\n# Development\n\nRight now all dev is done in dev cards.\n\n```bash\nyarn start\n```\n\nBrowse to:\n\nhttp://localhost:8923/cards.html\n\n## Run tests\n\n```bash\n# Optional but starts shadow cljs server for quicker test compile times.\nyarn start\nyarn test\n```\n\nDeploy notes\n\n- Update project.clj version\n- Update changelog\n- git commit new code\n- git tag the current version\n- push to remote\n- git push origin --tags\n- lein deploy clojars\n\n# License\n\nMIT License.\n\nCopyright © 2020 Daniel Vingo.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvingo%2Fcljs-styled-components","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdvingo%2Fcljs-styled-components","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvingo%2Fcljs-styled-components/lists"}