{"id":28411499,"url":"https://github.com/tendaysofclojure/hiccup-server-components","last_synced_at":"2025-06-23T23:31:59.116Z","repository":{"id":56871732,"uuid":"526699002","full_name":"TenDaysOfClojure/hiccup-server-components","owner":"TenDaysOfClojure","description":"A server-side rendering (SSR) library for Clojure web applications that facilitates defining, composing, organising, and unit testing user interface components.","archived":false,"fork":false,"pushed_at":"2022-09-16T17:46:27.000Z","size":365,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-09T13:23:05.107Z","etag":null,"topics":["clojure","hiccup","hiccup-interpreter","ssr","webapp"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TenDaysOfClojure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-08-19T17:37:44.000Z","updated_at":"2025-05-21T12:01:35.000Z","dependencies_parsed_at":"2022-08-20T18:31:58.932Z","dependency_job_id":null,"html_url":"https://github.com/TenDaysOfClojure/hiccup-server-components","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TenDaysOfClojure/hiccup-server-components","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TenDaysOfClojure%2Fhiccup-server-components","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TenDaysOfClojure%2Fhiccup-server-components/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TenDaysOfClojure%2Fhiccup-server-components/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TenDaysOfClojure%2Fhiccup-server-components/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TenDaysOfClojure","download_url":"https://codeload.github.com/TenDaysOfClojure/hiccup-server-components/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TenDaysOfClojure%2Fhiccup-server-components/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261575878,"owners_count":23179585,"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","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":["clojure","hiccup","hiccup-interpreter","ssr","webapp"],"created_at":"2025-06-02T16:17:59.984Z","updated_at":"2025-06-23T23:31:59.109Z","avatar_url":"https://github.com/TenDaysOfClojure.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Clojars Project](https://img.shields.io/clojars/v/net.clojars.t_d_c/hiccup-server-components.svg)](https://clojars.org/net.clojars.t_d_c/hiccup-server-components)\n\n# Hiccup Server Components\n\nA server-side rendering (SSR) library for Clojure web applications that facilitates **defining**, **composing**, **organising**, and **unit testing** user interface components, as well as **generating the associated HTML**. Based on the [Hiccup library](https://github.com/weavejester/hiccup)\n\nThe goal of this library is to **facilitate rapid web application development** and **increase maintainability of user interface code** by providing conventions and tools to model user interfaces.\n\n**Components** represent **modular**, **abstract pieces of the user interface** which are **composed into a larger**, **complex applications** with a high degree of abstraction.\n\nCan be used seamlessly with HTTP routing libraries such as [Reitit](https://github.com/metosin/reitit), [Compojure](https://github.com/weavejester/compojure), and directly with various [Clojure ring implementations](https://github.com/ring-clojure/ring) for generating HTML responses. Can also be used to generate static HTML files.\n\n# Table of contents\n\n- [Installation](#installation)\n- [Introduction](#introduction)\n- [Getting started: Building an example login page](#getting-started-building-an-example-login-page)\n- [Defining components](#defining-components)\n- [Composing components](#composing-components)\n- [Organising components](#organising-components)\n- [Generating HTML](#generating-html)\n- [Built-in components](#built-in-components)\n- [HTTP routing middleware](#http-routing-middleware)\n- [Full API documentation](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html)\n\n# Installation\n\n[![Clojars Project](https://img.shields.io/clojars/v/net.clojars.t_d_c/hiccup-server-components.svg)](https://clojars.org/net.clojars.t_d_c/hiccup-server-components)\n\nAdd the following dependancy to your Clojure projects to get the latest version:\n\n#### Clojure CLI/deps.edn:\n\n```clojure\nnet.clojars.t_d_c/hiccup-server-components {:mvn/version \"0.20.0\"}\n```\n\n#### Leiningen/Boot:\n\n```clojure\n[net.clojars.t_d_c/hiccup-server-components \"0.20.0\"]\n```\n\n[back to top](#table-of-contents)\n\n# Introduction\n\n### Using Hiccup to represent HTML\n\nThe [Hiccup library](https://github.com/weavejester/hiccup) is used for representing HTML in Clojure. It uses vectors to represent elements, and maps to represent an element's attributes.\n\nThe below Hiccup data represents the HTML for a typical login webpage:\n\n```Clojure\n;; HTML document\n[:html\n [:head\n  [:meta {:charset \"UTF-8\"}]\n  [:meta {:content \"width=device-width, initial-scale=1.0\", :name \"viewport\"}]\n\n  ;; Include CSS and javascript assets\n  [:link {:rel \"stylesheet\", :href \"/css/main.css\"}]\n  [:script {:src \"/js/app-bundle.js\"}]\n  [:title \"Login now\"]]\n [:body\n\n  ;; HTML form which posts to /login\n  [:form.input-form {:action \"/login\" :method \"POST\"}\n   [:h1.form-title \"Login now\"]\n   [:p.form-intro-text\n    \"Enter your email address and password to access your personal dashboard\"]\n\n   ;; Email input field with label\n   [:div.form-field\n    [:label.form-label {:for \"email-address\"} \"Email address\"]\n    [:input.text-input\n     {:id \"email-address\",\n      :name \"email-address\",\n      :autofocus true,\n      :type \"text\"}]]\n\n   ;; Password field with label\n   [:div.form-field\n    [:label.form-label {:for \"password\"} \"Password\"]\n    [:input.text-input\n     {:id \"password\", :name \"password\", :autofocus false, :type \"password\"}]]\n\n   ;; Form action buttons included primary button and cancel button\n   [:div.form-action-buttons\n    [:button.primary-submit-button {:type \"submit\"} \"Login now\"]\n\n    ;; Cancel button navigates back to '/home' using javascript\n    [:button.cancel-button\n     {:type \"button\", :onclick \"javascript:window.location='/home'\"}\n     \"Cancel\"]]]]]\n```\n\n### Further abstraction with Hiccup server components\n\nHiccup server components allows developers to represent web pages and user interface components with a high level of abstraction, leveraging the [Hiccup library](https://github.com/weavejester/hiccup).\n\n Using Hiccup server components We can represent the typical login webpage as follows:\n\n```clojure\n[:ux.layouts/html-doc {:title \"Login now\"}\n\n  [:ux.forms/form\n   {:title \"Login now\"\n    :intro-text \"Enter your email address and password to access your personal dashboard\"\n    :action \"/login\"}\n\n   [:ux.forms/text-input\n    {:label-text \"Email address\"\n     :element-name \"email-address\"\n     :auto-focus? true}]\n\n   [:ux.forms/text-input\n    {:label-text \"Password\"\n     :element-name \"password\"\n     :input-type \"password\"}]\n\n   [:ux.forms/action-buttons\n    [:ux.forms/primary-submit-button \"Login now\"]\n    [:ux.forms/cancel-button \"Back\" \"/home\"]]]]\n\n```\n\nWhich would produce the following web page:\n\n![](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/images/login-screen.png)\n\nWith the following HTML:\n\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n      \u003cmeta charset=\"UTF-8\"/\u003e\n      \u003cmeta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\"/\u003e\n      \u003clink href=\"/css/main.css\" rel=\"stylesheet\"/\u003e\n      \u003cscript src=\"/js/app-bundle.js\"\u003e\u003c/script\u003e\n      \u003ctitle\u003eLogin now\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003cform action=\"/login\" method=\"POST\" class=\"input-form\"\u003e\n          \u003ch1 class=\"form-title\"\u003eLogin now\u003c/h1\u003e\n          \u003cp class=\"form-intro-text\"\u003e\n            Enter your email address and password to access your personal\n            dashboard.\n          \u003c/p\u003e\n          \u003cdiv class=\"form-field\"\u003e\n              \u003clabel class=\"form-label\" for=\"email-address\"\u003eEmail address\u003c/label\u003e\n              \u003cinput autofocus=\"autofocus\" class=\"text-input\"\n                     id=\"email-address\"\n                     name=\"email-address\" type=\"text\"/\u003e\n          \u003c/div\u003e\n          \u003cdiv class=\"form-field\"\u003e\n              \u003clabel class=\"form-label\" for=\"password\"\u003ePassword\u003c/label\u003e\n              \u003cinput class=\"text-input\" id=\"password\" name=\"password\"\n                  type=\"password\"/\u003e\n          \u003c/div\u003e\n          \u003cdiv class=\"form-action-buttons\"\u003e\n              \u003cbutton class=\"primary-submit-button\" type=\"submit\"\u003eLogin now\u003c/button\u003e\n              \u003cbutton class=\"cancel-button\"\n                      onclick=\"javascript:window.location=\u0026apos;/home\u0026apos;\"\n                      type=\"button\"\u003eCancel\u003c/button\u003e\n          \u003c/div\u003e\n      \u003c/form\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n[back to top](#table-of-contents)\n\n# Getting started: Building an example login page\n\nThe goal of this introductory example is to demonstrate 95% of the features provided by this library. A basic understanding of the [Hiccup library](https://github.com/weavejester/hiccup) is a prerequisite.\n\nThe following example shows **how to build a simple login page**.\n\n### Step 1: Requiring the namespace\n\nThe public API for Hiccup Server Components is provided by the `ten-d-c.hiccup-server-components.core` namespace.\n\nThe first step, after including the library in your project, is to require the namespace:\n\n```clojure\n(ns introductory-example.core\n  (:require [ten-d-c.hiccup-server-components.core :as hc]))\n```\n\n### Step 2: Register your first component\n\nThe first component we'll register is an HTML document which involves the following steps:\n\n - Using the [`reg-component` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-reg-component) to register a new component using a qualified keyword.\n\n - Include `doc` and `examples` metadata (in the form of a clojure map) when registering the component to document the component.\n\n - Implement the components responsibilities using a pure function.\n\n```clojure\n(hc/reg-component\n ;; Keyword to uniquely identify the component:\n :ux.layouts/html-doc\n\n ;; Include meta data in the form of a map including `doc` and `examples` keys:\n {:doc\n  \"The main HTML document including a HEAD (with required CSS and Javascript\n    included) and BODY section.\n\n    This component is the basis for all top-level pages in the application.\n\n    The first parameter (a map) represents the component's options, followed by\n    a variable list of `child-elements` in the form of Hiccup data that will be\n    placed in the BODY.\n\n    Component options:\n\n    - `title`: The title of the HTML document (will populate the title tag\n       in the HEAD of the document)\"\n\n  :examples {\"With single child element\"\n             [:ux.layouts/html-doc\n              {:title \"One child element\"}\n              [:div \"Hello world\"]]\n\n             \"With multiple child elements\"\n             [:ux.layouts/html-doc\n              {:title \"Multiple child element\"}\n              [:h1 \"Hello world\"]\n              [:p \"This is a test\"]\n              [:a {:href \"/search\"} \"Try searching for more results\"]]}}\n\n ;; Pure function implementing the responsibilities of the component:\n (fn [{:keys [title] :as options} \u0026 child-elements]\n   [:html\n    [:head\n     [:meta {:charset \"UTF-8\"}]\n     [:meta {:content \"width=device-width, initial-scale=1.0\"\n             :name \"viewport\"}]\n     ;; Include application CSS and any javascript\n     [:link {:rel \"stylesheet\" :href \"/css/main.css\"}]\n     [:script {:src \"/js/app-bundle.js\"}]\n     ;; Include the title of the document\n     [:title title]]\n    ;; Variable child elements included in body element\n    [:body child-elements]]))\n```\n\nThe [`-\u003ehtml` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var--.3Ehtml) can be used to convert Hiccup data, which references the component using its qualified keyword, to HTML:\n\n```clojure\n(hc/-\u003ehtml\n [:ux.layouts/html-doc\n  {:title \"Multiple child element\"}\n  [:h1 \"Hello world\"]\n  [:p \"This is a test\"]\n  [:a {:href \"/search\"} \"Try searching for more results\"]])\n```\n\nThe following HTML is returned:\n\n```html\n\u003chtml\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"/\u003e\n    \u003cmeta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\"/\u003e\n    \u003clink href=\"/css/main.css\" rel=\"stylesheet\"/\u003e\n    \u003cscript src=\"/js/app-bundle.js\"\u003e\u003c/script\u003e\n    \u003ctitle\u003eMultiple child element\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003ch1\u003eHello world\u003c/h1\u003e\n    \u003cp\u003eThis is a test\u003c/p\u003e\n    \u003ca href=\"/search\"\u003eTry searching for more results\u003c/a\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### Step 3: Register components related to HTML forms\n\nThe next step is to register components that will be responsible for the HTML form which involves the following steps:\n\n- Using the [`reg-component` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-reg-component) to register a new component using a qualified keyword.\n\n- Including `doc` and `example` metadata (in the form of a clojure map) when registering the component to document the component.\n\n- Using a pure function, implement the components responsibilities that include:\n\n  - Building a HTML form with an `action` url\n\n  - Includes a standardised `title` and `intro-text` which enrich the all forms with text prompts.\n\n  - Allows for a variable amount of form elements which will be child elements of the form.\n\n\n```clojure\n(hc/reg-component\n ;; Keyword to uniquely identify the component:\n :ux.forms/form\n\n ;; Include meta data:\n {:doc\n  \"Builds an HTML form which will perform an HTTP POST to the given `action` URL\n   and provides a standardised `title`, optional `intro-text` which will be\n   displayed before form elements.\n\n   Along with the above options supports a variable amount of form elements.\n\n  Component options:\n\n  - `:action`: Specifies the URL where to send the form-data when a form is\n               submitted. e.g. \\\"/auth/login\\\"\n\n  - `:title`: (Required) The title text to be displayed at the top of the form\n              e.g. \\\"Login now\\\"\n\n  - `intro-text`: (Optional) Introduction text providing a summary for what the\n                  form is capturing as well as what happens on submission\n                  e.g. \\\"Enter your details to login and view your dashboard\\\".\"\n\n  :example [:ux.forms/form\n            {:action \"/auth/login\"             \n             :title \"Login now\"\n             :intro-text \"Provide your details to login and view your personal\n                          dashboard\"}\n            [:div\n             [:label {:for \"email-address\"} \"Email address\"]\n             [:input\n              {:name \"email-address\" :id \"email-address\" :type \"email\"}]]]}\n\n ;; Pure function implementing the responsibilities of the component:              \n (fn [{:keys [action title intro-text]} \u0026 form-elements]\n   [:form.input-form {:action action :method \"POST\"}\n    (when title [:h1.form-title title])\n    (when intro-text [:p.form-intro-text intro-text])\n    form-elements]))\n```\n\nThe [`-\u003ehtml` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var--.3Ehtml) can be used to convert Hiccup data, which references the component using its qualified keyword, to HTML:\n\n```clojure\n(hc/-\u003ehtml\n [:ux.forms/form\n  {:action \"/login\"\n   :title \"Login now\"\n   :intro-text \"Provide your details to login and view your personal\n                dashboard\"}\n  [:div\n   [:label {:for \"email-address\"} \"Email address\"]\n   [:input\n    {:name \"email-address\" :id \"email-address\" :type \"email\"}]]])\n```\n\nThe following HTML is returned:\n\n```html\n\u003cform action=\"/login\" method=\"POST\" class=\"input-form\"\u003e\n    \u003ch1 class=\"form-title\"\u003eLogin now\u003c/h1\u003e\n    \u003cp class=\"form-intro-text\"\u003eProvide your details to login and view your personal\n                              dashboard\u003c/p\u003e\n    \u003cdiv\u003e\n        \u003clabel for=\"email-address\"\u003eEmail address\u003c/label\u003e\n        \u003cinput id=\"email-address\" name=\"email-address\" type=\"email\"/\u003e\n    \u003c/div\u003e\n\u003c/form\u003e\n```\n\n### Step 4: Register components for form input\n\nThe next step is to register components that will be responsible for text input\nwhich, as with previous examples, involves using the [`reg-component` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-reg-component), including `doc` and `examples` metadata, and\nusing a pure function, implement the components responsibilities that include:\n\n```Clojure\n(hc/reg-component\n ;; Keyword to uniquely identify the component:\n :ux.forms/text-input\n\n ;; Include meta data:\n {:doc\n  \"A single-line text field of the given `input-type` that includes a label.\n\n   Component options:\n\n   - `:element-name`: Specifies the name of an input element which will be used\n                       as the name of the field when posting a FORM. Also used\n                       as the elements id.\n\n   - `label-text`: The text used for the associated label element.\n\n   - `input-type`: The type of form element e.g \\\"text\\\", \\\"email\\\",\n                   \\\"password\\\" etc.\n\n   - `auto-focus?`: Boolean value indicating that an element should be focused\n                    on page load.\"\n\n  :examples {\"Email field\" [:ux.forms/text-input\n                            {:auto-focus? true\n                             :label-text \"Email address\"\n                             :element-name \"email-address\"\n                             :input-type \"email\"}]\n\n             \"Password field\" [:ux.forms/text-input\n                               {:label-text \"Password\"\n                                :element-name \"password\"\n                                :input-type \"password\"}]}}\n\n ;; Pure function implementing the responsibilities of the component:\n (fn [{:keys [element-name label-text input-type auto-focus?]\n      :or {input-type \"text\" auto-focus? false}}]\n   [:div.form-field\n    [:label.form-label {:for element-name} label-text]\n    [:input.text-input\n     {:id element-name :name element-name\n      :autofocus auto-focus? :type input-type}]]))\n```\n\nThe [`-\u003ehtml` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var--.3Ehtml) can be used to convert Hiccup data, which references the component using its qualified keyword, to HTML:\n\n```clojure\n[:ux.forms/text-input\n  {:auto-focus? true\n   :label-text \"Email address\"\n   :element-name \"email-address\"\n   :input-type \"email\"}]\n```\n\nThe following HTML is returned:\n\n```html\n\u003cdiv class=\"form-field\"\u003e\n  \u003clabel class=\"form-label\" for=\"email-address\"\u003eEmail address\u003c/label\u003e\n  \u003cinput autofocus=\"autofocus\" class=\"text-input\"\n         id=\"email-address\" name=\"email-address\"\n         type=\"email\"/\u003e\n\u003c/div\u003e\n```\n\n### Step 5: Form buttons\n\nThe next step is to register components that will be responsible for form buttons.\n\nWe'll register two buttons  `:ux.forms/primary-submit-button` and `:ux.forms/cancel-button`\nwith metadata that document the button components:\n\n```clojure\n(hc/reg-component\n :ux.forms/primary-submit-button\n\n {:doc\n  \"Represents the button that will take the primary action which is submitting\n   the form. Button text is specified as the first and only parameter.\"\n\n  :examples {\"Login submit button\" [:ux.forms/primary-submit-button\n                                    \"Login now\"]\n\n             \"Save submit button\" [:ux.forms/primary-submit-button\n                                   \"Save\"]}}\n\n (fn [button-text]\n   [:button.primary-submit-button {:type \"submit\"} button-text]))\n\n\n(hc/reg-component\n :ux.forms/cancel-button\n\n {:doc \"Represents a button that is used to cancel an action and not submit a\n        form, for example going back to a previous page.\"\n\n  :examples {\"Login submit button\" [:ux.forms/cancel-button\n                                    \"Login now\"]\n\n             \"Save submit button\" [:ux.forms/cancel-button\n                                   \"Save\"]}}\n\n (fn [button-text url-to-redirect-to]\n   [:button.cancel-button\n    {:type \"button\"\n     :onclick (str \"javascript:window.location='\"\n                   url-to-redirect-to \"'\")}\n    button-text]))\n```\n\nIn addition to the submit and cancel button components we need a container element for form buttons\nthat will centre align and space the buttons consistently:\n\n```clojure\n(hc/reg-component\n :ux.forms/action-buttons\n {:doc\n  \"A container that will centre and consistently space buttons which represent\n   actions that can be taken on the form such as submitting the form or\n   going back to a previous page.\n\n   Usually placed at the bottom of a form after input fields.\n\n   Designed to work with form buttons such as `:ux.forms/primary-submit-button`\n   and `:ux.forms/cancel-button`\"\n\n  :example [:ux.forms/action-buttons\n            [:ux.forms/primary-submit-button \"Login now\"]\n            [:ux.forms/cancel-button \"Back\" \"/home\"]]}\n (fn [\u0026 children]\n   [:div.form-action-buttons\n    children]))\n```\n\nThe [`-\u003ehtml` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var--.3Ehtml) can be used to convert Hiccup data, which references the component using its qualified keyword, to HTML:\n\n```\n(hc/-\u003ehtml\n  [:ux.forms/action-buttons\n    [:ux.forms/primary-submit-button \"Login now\"]\n    [:ux.forms/cancel-button \"Back\" \"/home\"]])\n```\n\nThe following HTML is returned:\n\n```HTML\n\u003cdiv class=\"form-action-buttons\"\u003e\n    \u003cbutton class=\"primary-submit-button\" type=\"submit\"\u003eLogin now\u003c/button\u003e\n\n    \u003cbutton class=\"cancel-button\"\n            onclick=\"javascript:window.location=\u0026apos;/home\u0026apos;\"\n            type=\"button\"\u003e\n            Back\n    \u003c/button\u003e\n\u003c/div\u003e\n```\n\n### Step 6: Composing all form elements into a login screen and generating HTML\n\nWe have now registered components for the following form components:\n\n- `:ux.layouts/html-doc` - Builds the main HTML document.\n- `:ux.forms/form` - Builds the HTML form element.\n- `:ux.forms/text-input` - Builds a single-line text field.\n- `:ux.forms/action-buttons`- Layout container for buttons at the bottom of a form.\n- `:ux.forms/cancel-button` - A less pronounced button used for cancel actions.\n- `:ux.forms/primary-submit-button` - The primary button of the form.\n\nFrom this catalogue of form components we can compose another component that\nrepresents a typical login page a user would use to authenticate:\n\n\n```clojure\n(hc/reg-component\n :ux.pages/login\n\n {:doc \"The main login page for user authentication\"\n  :example [:ux.pages/login]}\n\n (fn []\n   [:ux.layouts/html-doc {:title \"Login now\"}\n\n    [:ux.forms/form\n     {:title \"Login now\"\n      :intro-text \"Enter your email address and password to access your personal dashboard\"\n      :action \"/login\"}\n\n     [:ux.forms/text-input\n      {:label-text \"Email address\"\n       :element-name \"email-address\"\n       :auto-focus? true}]\n\n     [:ux.forms/text-input\n      {:label-text \"Password\"\n       :element-name \"password\"\n       :input-type \"password\"}]\n\n     [:ux.forms/action-buttons\n      [:ux.forms/primary-submit-button \"Login now\"]\n      [:ux.forms/cancel-button \"Cancel\" \"/home\"]]]]))\n```\n\nWe can then generate the HTML by using the [`component-\u003ehtml` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-component-.3Ehtml):\n\n```clojure\n(hc/component-\u003ehtml :ux.pages/login)\n```\n\nWhich produces the following HTML:\n\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n      \u003cmeta charset=\"UTF-8\"/\u003e\n      \u003cmeta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\"/\u003e\n      \u003clink href=\"/css/main.css\" rel=\"stylesheet\"/\u003e\n      \u003cscript src=\"/js/app-bundle.js\"\u003e\u003c/script\u003e\n      \u003ctitle\u003eLogin now\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003cform action=\"/login\" method=\"POST\" class=\"input-form\"\u003e\n          \u003ch1 class=\"form-title\"\u003eLogin now\u003c/h1\u003e\n          \u003cp class=\"form-intro-text\"\u003e\n            Enter your email address and password to access your personal\n            dashboard.\n          \u003c/p\u003e\n          \u003cdiv class=\"form-field\"\u003e\n              \u003clabel class=\"form-label\" for=\"email-address\"\u003eEmail address\u003c/label\u003e\n              \u003cinput autofocus=\"autofocus\" class=\"text-input\"\n                     id=\"email-address\"\n                     name=\"email-address\" type=\"text\"/\u003e\n          \u003c/div\u003e\n          \u003cdiv class=\"form-field\"\u003e\n              \u003clabel class=\"form-label\" for=\"password\"\u003ePassword\u003c/label\u003e\n              \u003cinput class=\"text-input\" id=\"password\" name=\"password\"\n                  type=\"password\"/\u003e\n          \u003c/div\u003e\n          \u003cdiv class=\"form-action-buttons\"\u003e\n              \u003cbutton class=\"primary-submit-button\" type=\"submit\"\u003eLogin now\u003c/button\u003e\n              \u003cbutton class=\"cancel-button\"\n                      onclick=\"javascript:window.location=\u0026apos;/home\u0026apos;\"\n                      type=\"button\"\u003eCancel\u003c/button\u003e\n          \u003c/div\u003e\n      \u003c/form\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n[back to top](#table-of-contents)\n\n# Defining components\n\n**\u003cu\u003eDefining\u003c/u\u003e** components is achieved by using the [`reg-component` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-reg-component), which associates a qualified keyword with either a function (for dynamic content) or a vector or string (for static content) that represents a piece of the user interface.\n\nIn turn, components can then be referenced by their qualified keyword in Hiccup data, much like HTML elements, allowing for composition.\n\nThe Hiccup server components library is included in your code by requiring the `ten-d-c.hiccup-server-components.core` namespace:\n\n```Clojure\n(ns your-web-app.ux.core\n  (:require [ten-d-c.hiccup-server-components.core :as hc]))\n```\n\n### Registering component functions\n\nWhen a component returns dynamic content and accepts parameters that affect its output, it can be registered using a function.\n\nThe below example registers a component `:ux.components/primary-submit-button` which abstracts a HTML submit button:\n\n```clojure\n(hc/reg-component :ux.components/primary-submit-button\n                  (fn [text attributes]\n                    [:button.primary-button.submit-button\n                     (assoc attributes :type \"submit\")\n                     text]))\n```\n\nThe above component function accepts a `text` parameter (representing the button text) as well as an `attributes` parameter (representing arbitrary attributes of the button). In addition, a `primary-button` \u0026 `submit-button` css class are added to the button using the [Hiccup CSS-like shortcut](https://github.com/weavejester/hiccup/wiki/Syntax#css-style-sugar).\n\nWhen registering a component in this manner the function should meet the following requirements:\n\n1.) Should be a [pure function](https://practical.li/clojure/thinking-functionally/pure-functions.html):\n\n  - A pure function is free of side effects, does not change any other part of the system, and is not affected by any other part of the system.\n\n  - A pure function's return values are identical for identical arguments.\n\n2.) Should have an intuitive argument structure and provide sensible defaults. This will be covered in more detail later.\n\n3.) Should return either a vector representing Hiccup data or a string.\n\nTo expand on the previous example and highlight a different approach to function arguments, we could define a `:ux.components/cancel-button` as follows:\n\n```clojure\n(hc/reg-component\n  :ux.components/cancel-button\n  (fn [\u0026 {:keys [text on-cancel]}]\n    [:button.cancel-button\n     {:type \"button\" :onclick on-cancel}\n     text]))\n```\n\nThe above component function destructures a `text` parameter (representing the button text) as well as an `on-cancel` handler (representing the client-side `onclick` handler of the button). In addition, a `cancel-button` css class is added to the button.\n\n### Component metadata\n\nWhen a component is registered using the [`reg-component` function](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-reg-component), metadata in the form of a map can be included as the second parameter to help document the component and its parameters as well as provide examples of component usage.\n\nWhile arbitrary metadata can be provided, the convention of component metadata includes the following keys:\n\n- `:doc` - a docstring describing the component and its parameters,\n- `:example` - Hiccup data showing a single example usage of the component\n- `:examples` - A map with keys that describe the example and values that are Hiccup data, allowing for multiple examples to be provided.\n\nThe below example registers a `:ux.layouts/centred-container` component with metadata including a `doc` and a `example` key:\n\n```clojure\n(hc/reg-component\n :ux.layouts/centred-container\n\n {:doc\n   \"A simple container to horizontally centre content. Accepts one or more child\n    elements.\"\n  :example [:ux.layouts/centred-container\n            [:h1 \"Hello world\"]]}\n\n (fn [\u0026 children]\n   [:div.centred-container children]))\n```\n\nThe below example registers a `:ux.layouts/centred-container` component with metadata including a `doc` and a `examples` key:\n\n```clojure\n(hc/reg-component\n :ux.layouts/centred-container\n\n {:doc\n   \"A simple container to horizontally centre content. Accepts a variable amount\n    of child elements.\"\n\n  :examples\n  {\"With a single child element\" [:ux.layouts/centred-container\n                                  [:h1 \"Hello world\"]]\n\n   \"With multiple child elements\" [:ux.layouts/centred-container\n                                   [:h1 \"Hello world\"]\n                                   [:p \"Hello this is a test\"]\n                                   [:p \"This is a second paragraph\"]]}}\n\n (fn [\u0026 children]\n   [:div.centred-container children]))\n```\n\n\n### Registering component vectors or strings\n\nWhen a component returns static content and does not require any input parameters that affect its output, it can be registered using either a vector (representing Hiccup data) or a string (representing either plain text or an HTML string).\n\nThe below example registers a component `:ux.components/sale-banner` with a vector representing Hiccup data:\n\n```clojure\n(hc/reg-component\n  :ux.components/sale-banner\n  [:div.sale-banner\n   [:strong \"50% off sale!\"] \" Buy any item on promotion and get 50% off. \"\n   [:a {:href \"/promotions\"} \"View promotions\"]])\n```\n\nThe below examples register plain text components representing page titles. Plain text components can be useful for having text content available as a component:\n\n```clojure\n(hc/reg-component :ux.page-titles/login-page \"Login now\")\n(hc/reg-component :ux.page-titles/dashboard-page \"Welcome to your dashboard\")\n(hc/reg-component :ux.page-titles/register-page \"Register your account now\")\n```\n\nBy default, all strings are escaped, however, components can be registered as raw HTML strings that won't be escaped by including the `:hiccup-server-components/raw-html? true` option as the second parameter to `reg-component`.\n\nUsing Hiccup data structure is always preferred over raw HTML strings, but this option is included for completeness:\n\n```clojure\n(hc/reg-component\n  :ux.components/sale-banner-raw\n  ;; Including this option will prevent HTML from being escaped\n  {:hiccup-server-components/raw-html? true}\n  \"\u003cdiv class='sale-banner'\u003e\n     \u003cstrong\u003e50% off sale!\u003c/strong\u003e Buy any item on promotion and get 50% off.\n     \u003ca href='/promotions'\u003eGo to promotions\u003c/a\u003e\n   \u003c/div\u003e\")\n```\n\n[back to top](#table-of-contents)\n\n# Composing components\n\nOnce components have been registered they can be **referenced in Hiccup data by their qualified keywords** much like any other HTML element **allowing for composition**.\n\nThe below example shows a centred container div with a \"side bar\" (containing a list of links representing a menu) and a \"main content\" area displaying content based on what is selected in the side bar:\n\n```clojure\n[:div.centred-container\n  [:div.side-bar\n    [:ul\n      [:li.active [:a {:href \"/dashboard\"} \"Dashboard\"]]\n      [:li [:a {:href \"/your-profile\"} \"Your profile\"]]\n      [:li [:a {:href \"/manage-users\"} \"Manage users\"]\n      [:li [:a {:href \"/logout\"} \"Logout\"]]]]]\n\n  [:div.main-content\n   [:h1.main-title \"Welcome to your dashboard\"]\n   [:p \"This is your dashboard, this is a test.\"]]]\n```\n\nIn the above example `div`, `ul`, `li`, `a`, `h1` and `p` HTML elements are composed into an abstract structure that represents the \"side bar\" and \"main content\" areas, which is centred by a parent container.\n\nAs a first step, we can extract both the \"side bar\" and the \"main content\" areas into vector components that initially represent static content:\n\n```clojure\n(hc/reg-component\n :ux.components/side-bar\n [:div.side-bar\n  [:ul\n   [:li.active [:a {:href \"/dashboard\"} \"Dashboard\"]]\n   [:li [:a {:href \"/your-profile\"} \"Your profile\"]]\n   [:li [:a {:href \"/manage-users\"} \"Manage users\"]\n   [:li [:a {:href \"/logout\"} \"Logout\"]]]]])\n\n\n(hc/reg-component\n :ux.components/main-content\n [:div.main-content\n  [:h1.main-title \"Welcome to your dashboard\"]\n  [:p \"This is your dashboard, this is a test.\"]])\n```\n\nWe can then reference these components by their qualified keyword in Hiccup data (much like any other HTML element), effectively providing a level of abstraction:\n\n```clojure\n[:div.centred-container\n  [:ux.components/side-bar]\n  [:ux.components/main-content]]\n```\n\nTaking it a step further, we can also abstract the \"centred container\" div element. Parent/container elements often have a variable number of child elements that are accommodated by using a [variadic function](https://clojure.org/guides/learn/functions#_variadic_functions) (i.e. a function with a variable number of arguments):\n\n```clojure\n(hc/reg-component\n :ux.layouts/centred-container\n {:doc \"A simple container to horizontally center content\"\n  :examples\n  {\"With a single child element\" [:ux.layouts/centred-container\n                                   [:p \"This is a test\"]]\n\n   \"With multiple child elements\" [:ux.layouts/centred-container\n                                    [:h1 \"Hello world\"]\n                                    [:p \"Hello this is a test\"]\n                                    [:p \"This is a second paragraph\"]]}}\n ;; Variadic function with variable arguments representing child elements.\n (fn [\u0026 children]\n   [:div.centred-container children]))\n```\n\nWe can then further abstract the example as follows:\n\n```clojure\n[:ux.layouts/centred-container\n  [:ux.components/side-bar]\n  [:ux.components/main-content]]\n```\n\nWhile for the sake of example, the \"side bar\" and \"main content\" components were initially registered as static content (using a vector representing Hiccup data), these components should become dynamic by using component functions.\n\n### Converting to a dynamic side bar component\n\nTo convert the \"side bar\" into a dynamic component we can take the following steps:\n\n1. **Define the component's responsibilities**: The component is responsible for constructing a \"side bar\" element that includes a list of links representing a menu. It is also responsible for determining which of the links in the menu is \"active\".\n\n2. **Define component parameters**: The component accepts a map as parameter that includes two keys: `active-url` representing the url of the menu link that should be marked as active and `menu-items` which is a vector of maps that include a `href` and `label` key which represent the menu items.\n\n    An example of referencing the component with parameters:\n\n    ```clojure\n    [:ux.components/side-bar\n      {:active-url \"/dashboard\"\n       :menu-items [{:href \"/dashboard\" :label \"Dashboard\"} ;; marked as active\n                    {:href \"/your-profile\" :label \"Your profile\"}\n                    {:href \"/manage-users\" :label \"Manage users\"}\n                    {:href \"/logout\" :label \"Logout\"}]}]\n    ```\n\n\n 3. **Register a component** that meets the above requirements:\n\n    ```clojure\n    (hc/reg-component\n     :ux.components/side-bar\n     ;; Accepts `active-url` and `menu-items`\n     (fn [{:keys [active-url menu-items]}]\n       [:div.side-bar\n        [:ul\n         ;; Builds a list of menu items\n         (for [{:keys [href label]} menu-items]\n           ;; Determines if the menu item is active based on the `active-url`\n           ;; and assigns a \"active\" CSS class\n           (let [css-class (when (= href active-url)\n                             \"active\")]\n             [:li {:class css-class}\n              [:a {:href href} label]]))]]))\n    ```\n\n4. When a component is registered, meta data in the form of a map can be included as the second parameter to help document the component as well as its parameters.\n\n   While arbitrary metadata can be provided, based on the developers needs, the two common keys are `doc` which is a string describing the component and it's parameters and `example` which is Hiccup data showing example usage of the component.\n\n   Below is an expanded example of the side bar that includes `doc` and `example` metadata:\n\n    ```clojure\n    (hc/reg-component\n     :ux.components/side-bar\n     {:doc\n       \"Responsible for constructing a \\\"side bar\\\" element that includes a list\n        of links representing a menu. It is also responsible for determining\n        which of the menu items are \\\"active\\\".\n\n        Supported parameters:\n\n        `:active-url` (optional) - The url of the menu item that should be\n                                   marked as active. e.g. \\\"/your-profile\\\"\n\n        `:menu-items` (required) - A vector of maps that include a `href` and\n                                   `label` key which represent the menu items.\n                                   e.g. `[{:href \\\"/your-profile\\\"\n                                           :label \\\"Your profile\\\"}\n                                          {:href \\\"/manage-users\\\"\n                                           :label \\\"Manage users\\\"}]`\"\n\n      :example [:ux.components/side-bar\n                {:active-url \"/dashboard\"\n                 :menu-items [{:href \"/dashboard\" :label \"Dashboard\"}\n                              {:href \"/your-profile\" :label \"Your profile\"}\n                              {:href \"/manage-users\" :label \"Manage users\"}\n                              {:href \"/logout\" :label \"Logout\"}]}]}\n     (fn [{:keys [active-url menu-items]}]\n       [:div.side-bar\n        [:ul\n         ;; Builds a list of menu items\n         (for [{:keys [href label]} menu-items]\n           ;; Determines if the menu item is active based on the `active-url`\n           ;; and assigns a \"active\" CSS class\n           (let [css-class (when (= href active-url)\n                             \"active\")]\n             [:li {:class css-class}\n              [:a {:href href} label]]))]]))\n    ```\n\n\n### Converting to a dynamic main content component\n\nTo convert the \"main content\" into a dynamic component we can do the following:\n\n1. **Define the components responsibilities**: The component is responsible for constructing a \"main content\" element that includes a title element (`h1`) as well as variable amount of child elements.\n\n2. **Define component parameters**: The component accepts a map as its first parameter that includes a `title` keys representing the title shown in the main area. The second parameter is a list of variable child elements (using Clojure's [variadic function](https://clojure.org/guides/learn/functions#_variadic_functions) syntax) that will be displayed within the main content area.\n\n    An example of referencing the components with parameters:\n\n    ```clojure\n    [:ux.components/main-content\n      ;; Component options\n      {:title \"Welcome to your dashboard\"}\n      ;; Variable child elements\n      [:p \"This is your dashboard, this is a test.\"]\n      [:p \"Use the following link to take an action \"\n        [:a {:href \"/some-action\"} \"Take action now\"]]]\n    ```\n\n 3. Register a component (including `doc` and `example` metadata) that meets the above requirements:\n\n    ```clojure\n    (hc/reg-component\n     :ux.components/main-content\n     {:doc\n       \"Responsible for constructing a \\\"main content\\\" element that includes a\n        title element (`h1`) as well as variable amount of child elements.\n\n        Accepts a map as the first parameter that should include a `title` keys\n        representing the title shown in the main area.\n\n        The second parameter is a list of variable child elements that will be\n        displayed within the main content area.\"\n\n      :example [:ux.components/main-content\n                {:title \"Welcome to your dashboard\"}\n                [:p \"This is your dashboard, this is a test.\"]\n                [:p \"Use the following link to take an action \"\n                 [:a {:href \"/some-action\"} \"Take action now\"]]]}\n     (fn [{:keys [title]} \u0026 children]\n       [:div.main-content\n        ;; Title always shown\n        [:h1.main-title title]\n        ;; Child elements defined by consumer of component.\n        children]))\n    ```        \n\nWith both the \"side bar\" and \"main content\" components now being dynamic we can rewrite the original Hiccup data using the new components which results in a higher level of abstraction.\n\nBefore:\n\n```clojure\n[:div.centred-container\n  [:div.side-bar\n    [:ul\n      [:li.active [:a {:href \"/dashboard\"} \"Dashboard\"]]\n      [:li [:a {:href \"/your-profile\"} \"Your profile\"]]\n      [:li [:a {:href \"/manage-users\"} \"Manage users\"]\n      [:li [:a {:href \"/logout\"} \"Logout\"]]]]]\n\n  [:div.main-content\n   [:h1.main-title \"Welcome to your dashboard\"]\n   [:p \"This is your dashboard, this is a test.\"]]]\n```\n\nAfter:\n\n```clojure\n[:ux.layouts/centred-container\n\n  [:ux.components/side-bar\n    {:active-url \"/dashboard\"\n     :menu-items [{:href \"/dashboard\" :label \"Dashboard\"}\n                  {:href \"/your-profile\" :label \"Your profile\"}\n                  {:href \"/manage-users\" :label \"Manage users\"}\n                  {:href \"/logout\" :label \"Logout\"}]}]\n\n  [:ux.components/main-content\n    {:title \"Welcome to your dashboard\"}\n    [:p \"This is your dashboard, this is a test.\"]\n    [:p \"Use the following link to take an action \"\n      [:a {:href \"/some-action\"} \"Take action now\"]]]]\n```\n\n\nWould produce the following HTML:\n\n```html\n\u003cdiv class=\"centred-container\"\u003e\n  \u003cdiv class=\"side-bar\"\u003e\n    \u003cul\u003e\n      \u003cli class=\"active\"\u003e\n          \u003ca href=\"/dashboard\"\u003eDashboard\u003c/a\u003e\n      \u003c/li\u003e      \n      \u003cli\u003e\n          \u003ca href=\"/your-profile\"\u003eYour profile\u003c/a\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n          \u003ca href=\"/manage-users\"\u003eManage users\u003c/a\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n          \u003ca href=\"/logout\"\u003eLogout\u003c/a\u003e\n      \u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"main-content\"\u003e\n    \u003ch1 class=\"main-title\"\u003eWelcome to your dashboard\u003c/h1\u003e\n    \u003cp\u003eThis is your dashboard, this is a test.\u003c/p\u003e\n    \u003cp\u003e\n      Use the following link to take an action\n      \u003ca href=\"/some-action\"\u003eTake action now\u003c/a\u003e\n    \u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n[back to top](#table-of-contents)\n\n# Organising components\n\nOrganising components is done through the use of **qualified keywords**, **Clojure namespaces**, and **source code structure** to create a component catalogue.\n\nWhen registering a component a qualified keyword must be used. Qualified keywords make components unique, provide a means of logical categorisation, and allow component references to be quickly identified when they are composed into Hiccup data.\n\n### Convention for organising components\n\nThe following namespace and source code structure is used to organise components:\n\n1. A top-level/parent directory (usually `src/ux`) with a `src/ux/core.clj` file representing the top level component namespace `ux.core`, the main entry point for all components. Requiring this namespace in other areas of your application will make all components available to consuming code.\n\n2. Child source files in the top-level/parent directory representing secondary component namespaces to group logically related components:\n\n    Examples of secondary namespaces in parent directory `src/ux`:\n\n    - Namespace: `ux.layouts` in file `src/ux/layouts.clj`\n    - Namespace `ux.buttons` in file `src/ux/buttons.clj`\n    - Namespace `ux.pages` in file `src/ux/pages.clj`\n\n3. Secondary component namespaces are made available by requiring them in the main component namespace:\n\n    ```clojure\n    ;; File src/ux/core.clj\n\n    (ns ux.core ;; Main component namespace\n      ;; Require secondary components, making them generally available.\n      (:require [ux.layouts]\n                [ux.buttons]\n                [ux.pages]))\n    ```\n\n4. Tertiary component namespaces can be used for further separation of components and have their own subdirectory under the main parent directory.\n\n    - Example: namespace: `ux.layouts.html-doc` in file `src/ux/layouts/html_doc.clj`\n\n5. Tertiary component namespaces are made available by requiring them in the relevant secondary component namespace:\n\n    ```clojure\n    ;; File src/ux/layouts.clj\n\n    (ns ux.layouts ;; Secondary component namespace\n      ;; Include tertiary components\n      (:require [ux.layouts.html-doc]))\n    ```\n\nThis convention should cover 90% of component organisation needs and allow developers to build a component catalogue.\n\nBelow is an example directory structure showing component source file organisation:\n\n```bash\nux                   # Top-level/parent directory\n├── core.clj         # File: Main component namespace `ux.core`\n├── layouts.clj      # File: Secondary `ux.layouts` namespace\n├── layouts          # Directory: Tertiary component namespaces for layouts\n│   └── html_doc.clj # File: Tertiary `ux.layouts.html-doc` namespace\n├── buttons.clj      # File: Secondary `ux.buttons` namespace\n└── pages.clj        # File: Secondary `ux.pages` namespace\n```\n\n### Main entry point namespace for components\n\nIn order to make your components generally available in your application we'll employ standard Clojure source code and namespace organisation techniques.\n\nAs an example we'll create a `ux` directory containing a file `src/ux/core.clj` which represents the top level component namespace `ux.core` and main entry point for all your components. Requiring this file in other namespaces in your application will make all components available to consuming code.\n\nInitially the file includes only the namespace definition:\n\n```clojure\n;; File src/ux/core.clj\n(ns ux.core)\n```\n\n### Secondary component namespaces and source files\n\nOnce the top-level component namespace has been created the next step is to create Clojure source files representing secondary component namespaces.\n\nFor example if we have layout components we would have a `ux.layouts` namespace in file `src/ux/layouts.clj`. This file represents the main entry point for layout components.\n\nBelow we define the `ux.layouts` namespace by creating the `src/ux/layouts.clj` file and registering a couple of components in the `:ux.layouts` namespace:\n\n```clojure\n;; File src/ux/layouts.clj\n\n(ns ux.layouts\n  (:require [ten-d-c.hiccup-server-components.core :as hc]))\n\n(hc/reg-component :ux.layouts/html-doc \"...\")\n(hc/reg-component :ux.layouts/centred-container \"...\")\n(hc/reg-component :ux.layouts/centred-screen \"...\")\n(hc/reg-component :ux.layouts/section \"...\")\n(hc/reg-component :ux.layouts/form \"...\")\n(hc/reg-component :ux.layouts/footer \"...\")\n\n```\n\nTo expand on this we could have a `ux.buttons` namespace in the `src/ux/buttons.clj` file which represents the main entry point for button components:\n\n```clojure\n;; File src/ux/buttons.clj\n\n(ns ux.buttons\n  (:require [ten-d-c.hiccup-server-components.core :as hc]))\n\n(hc/reg-component :ux.buttons/primary-button \"...\")\n(hc/reg-component :ux.buttons/secondary-button \"...\")\n(hc/reg-component :ux.buttons/tertiary-button \"...\")\n(hc/reg-component :ux.buttons/info-button \"...\")\n(hc/reg-component :ux.buttons/success-button \"...\")\n(hc/reg-component :ux.buttons/danger-button \"...\")\n(hc/reg-component :ux.buttons/warning-button \"...\")\n\n```\n\nWe could have a `ux.pages` namespace in the `src/ux/pages.clj` file which represents the main entry point for high level webpages:\n\n```clojure\n;; File src/ux/pages.clj\n\n(ns ux.pages\n  (:require [ten-d-c.hiccup-server-components.core :as hc]))\n\n(hc/reg-component :ux.pages/home \"...\")\n(hc/reg-component :ux.pages/dashboard \"...\")\n(hc/reg-component :ux.pages/your-profile \"...\")\n(hc/reg-component :ux.pages/manage-users \"...\")\n```\n\n### Including secondary component namespaces in main entry point file\n\nTo make these components available to the application we would then require these namespaces (`ux.layouts` `ux.buttons` and `ux.pages`) in the main component entry point namespace `ux.core` defined in file `src/ux/core.clj`:\n\n```clojure\n;; File src/ux/core.clj\n\n(ns ux.core\n  ;; Require second level of components, making them generally available.\n  (:require [ux.layouts]\n            [ux.buttons]\n            [ux.pages]))\n```\n\n### Tertiary component namespaces and source files\n\nSome components may be complex enough or have thorough documentation to warrant their own namespace or it might be the developers preference to create a high degree of separation between components.\n\nFor example, lets say we had a `:ux.layouts/html-doc` component that supported many options, included thorough documentation and was more complex than other layouts. We could create a further separation by creating a dedicated `ux.layouts.html-doc` namespace and source file `src/ux/layouts/html_doc.clj`\n\n```clojure\n;; File src/ux/layouts/html_doc.clj\n\n(ns ux.layouts.html-doc\n  (:require [ten-d-c.hiccup-server-components.core :as hc]))\n\n(hc/reg-component :ux.layouts/html-doc \"...\" )\n```\n\nWe could then require this tertiary source file in the layout namespace `ux.layouts` to make it generally available.\n\nSince the `ux.layouts` namespace is already required in the main component entry point namespace `ux.core`, the tertiary component `:ux.layouts/html-doc` will automatically become available:\n\n```clojure\n;; File src/ux/layouts.clj\n\n(ns ux.layouts\n  (:require [ux.layouts.html-doc] ;; include the html-doc\n            [ten-d-c.hiccup-server-components.core :as hc]))\n\n;; `:ux.layouts/html-doc` component now reginsred in `ux.layouts.html-doc` namespace.\n\n(hc/reg-component :ux.layouts/centred-container \"...\")\n(hc/reg-component :ux.layouts/centred-screen \"...\")\n(hc/reg-component :ux.layouts/section \"...\")\n(hc/reg-component :ux.layouts/form \"...\")\n(hc/reg-component :ux.layouts/footer \"...\")            \n```\n\n[back to top](#table-of-contents)\n\n# Generating HTML\n\nThe below functions are provided to generate HTML from Hiccup data that can include component references:\n\n- [`-\u003ehtml`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var--.3Ehtml) Takes `hiccup-data`, that can include component references, and returns the generated HTML.\n\n- [`-\u003ehtml-file`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var--.3Ehtml-file) Takes a `file-path` and `hiccup-data`, that can include component references, and saves the generated HTML to the given `file-path`.\n\n- [`component-\u003ehtml`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-component-.3Ehtml) Generates and returns HTML of a component with the given `component-element-name`.\n\n- [`component-\u003ehtml-file`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-component-.3Ehtml-file) Generates the HTML of a component with the given `component-element-name` and\nsaves the output to the given `file-path`.\n\nSee [API docs](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html) for details.\n\n[back to top](#table-of-contents)\n\n\n# Built-in components\n\nHiccup server components ships with a number of built-in components that are common to web app development.\n\nSee the [built-in component documentation](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html) for more details on built-in components.\n\n**Summary of built-in components:**\n\n- [`:ux/css-classes`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-css-classes): Constructs a list of one or more css classes that can be used as the  \"class\" attribute of HTML elements.\n\n\n- [`:ux/fragment`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-fragment): Allows for returning multiple child elements without the need for a  parent element.\n\n\n- [`:ux/html`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-html): Used for including strings that contain HTML markup, this component converts  the provided `html` into an unescaped string, allowing the HTML to be  rendered by the browser.\n\n\n- [`:ux/html-template`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-html-template): Returns an unescaped HTML string where interpolated variables are replaced using values in  the map provided by `variable-substitution-map` allowing for templated HTML strings.\n\n\n- [`:ux/html5-doc`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-html5-doc): Constructs a HTML5 document with the correct DOCTYPE using the given `document`  as child elements (e.g head, body) of the \u0026lt;html\u003e tag.\n\n\n- [`:ux/include-javascripts`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-include-javascripts): Includes one or more \u0026lt;script\u003e tags that link to external javascript files  through the `src` attribute.\n\n\n- [`:ux/include-stylesheets`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-include-stylesheets): Includes one or more \u0026lt;link\u003e tags that link to external style sheets.\n\n\n- [`:ux/javascript`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-javascript): Used for including unescaped, executable javascript in Hiccup data.\n\n\n- [`:ux/javascript-tag`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-javascript-tag): Wraps the supplied `javascript-lines` in a \u0026lt;script\u003e tag which executes the javascript in the  web browser.\n\n\n- [`:ux/string-template`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-string-template): Returns a string where interpolated variables are replaced using values in  the map provided by `variable-substitution-map` allowing for templated strings.\n\n\n- [`:ux/style-tag`](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/component-docs/index.html#ux-style-tag): A \u0026lt;style\u003e tag used to define style information (CSS) for a document.\n\n# HTTP routing middleware\n\nRing middleware that will generate HTML using Hiccup server components conventions\nand set the `:body` of the response to the generated HTML.\n\nWorks with [Compojure](https://github.com/weavejester/compojure) and\n[Reitit](https://github.com/metosin/reitit) routing libraries as well\nas Ring compatible HTTP servers.\n\nHTTP route handlers configured with this middleware can return a map including\nthe following keys which will result in HTML being set on the response body:\n\n- `:hsc/component`: The qualified keyword of the component to use to generate\n                   HTML that will be set as the `:body` of the response.\n                   Component params can be supplied with the `:hsc/params`\n                   key.\n\n- `:hsc/params` (Optional): Used in conjunction with the `:hsc/component` key,\n               represents params that will be passed to the component.\n\n- `:hsc/html`: Hiccup data (vectors describing HTML), that can include\n              component references, that will be used to generate HTML that\n              will be set as the `:body` of the response.\n\nExample of [Compojure](https://github.com/weavejester/compojure) routes with\nmiddleware configured:\n\n```clojure\n(ns http-routing.compojure\n  (:require [compojure.core :refer :all]\n            [ten-d-c.hiccup-server-components.core :as hc]))\n\n(compojure.core/defroutes app\n\n  ;; Generates and returns the HTML for the `:ux.pages/home` component, no\n  ;; component params are provided.\n  (GET \"/\" []\n       {:hsc/component :ux.pages/home})\n\n\n  ;; Generates and returns the HTML for the `:ux.pages/dashboard` component,\n  ;; passing the component the `hsc/params` key as params.\n  (GET \"/dashboard\" []\n       {:hsc/component :ux.pages/dashboard\n        :hsc/params {:username \"bobsmith\"\n                     :email-address \"bobsmith@somemail.net\"}})\n\n\n  ;; Generates and returns the HTML from Hiccup data (which can include\n  ;; component refererences) in the `:hsc/html` key.\n  (GET \"/testing\" []\n       {:hsc/html [:ux.layouts/html-doc {:title \"A test page\"}\n                   [:div\n                    [:h1.text-3xl \"Hello world From HTML\"]\n                    [:p \"This is a test\"]]]}))\n\n\n(def web-app (-\u003e app\n                 (hc/wrap-response-middleware)))\n```\n\nExample of [Reitit](https://github.com/metosin/reitit) routes with\nmiddleware configured:\n\n```clojure\n(ns http-routing.reitit\n  (:require [reitit.ring :as ring]\n            [ten-d-c.hiccup-server-components.core :as hc]))\n\n\n(def web-app\n  (ring/ring-handler\n   (ring/router\n    [[\"/\" {:handler (fn [_]\n                      {:hsc/component :ux.pages/home})}]\n\n     [\"/dashboard\"\n      {:get\n       {:handler\n        (fn [_]\n          {:hsc/component :ux.pages/dashboard\n           :hsc/params {:username \"bobsmith\"\n                        :email-address \"bobsmith@somemail.net\"}})}}]\n\n     [\"/testing\"\n      {:get\n       {:handler\n        (fn [_]\n          {:hsc/html [:ux.layouts/html-doc {:title \"A test page\"}\n                      [:div\n                       [:h1.text-3xl \"Hello world From HTML\"]\n                       [:p \"This is a test\"]]]})}}]]\n\n    {:data {:middleware [hc/wrap-response-middleware]\n            :enable true}})))\n```\n\nSee [`wrap-response-middleware` documentation](https://tendaysofclojure.github.io/hiccup-server-components-api-docs/ten-d-c.hiccup-server-components.core.html#var-wrap-response-middleware) for more details.\n\n\n[back to top](#table-of-contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftendaysofclojure%2Fhiccup-server-components","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftendaysofclojure%2Fhiccup-server-components","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftendaysofclojure%2Fhiccup-server-components/lists"}