ten-d-c.hiccup-server-components.core
A 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
Components represent modular, abstract pieces of the user interface which are composed into a larger, complex applications with a high degree of abstraction.
Can be used seamlessly with HTTP routing libraries such as Reitit, Compojure, and directly with various Clojure ring implementations for generating HTML responses. Can also be used to generate static HTML files.
See full README for examples and further details.
->hiccup
(->hiccup hiccup-data local-components)
(->hiccup hiccup-data)
Processes components in the provided hiccup-data
(vectors describing HTML) and returns expanded Hiccup data (vectors describing HTML).
-
hiccup-data
: The hiccup data (vectors describing HTML) to process which includes references to components. -
local-components
: (Optional) A map of component configuration. Components defined here will overwrite components registered with->reg-component
for this function call only.
->html
(->html hiccup-data local-components)
(->html hiccup-data)
Takes hiccup-data
(vectors describing HTML), that can include component references, and returns the generated HTML.
-
hiccup-data
: The hiccup data (vectors describing HTML) to process which may include references to components. -
local-components
: (Optional) A map of component configuration. Components defined here will overwrite components registered with->reg-component
for this function call only.
->html-file
(->html-file file-path hiccup-data)
(->html-file file-path hiccup-data local-components)
Takes a file-path
and hiccup-data
(vectors describing HTML), that can include component references, and saves the generated HTML to the given file-path
.
-
file-path
: The file path to save the outputed HTML to. -
hiccup-data
: The hiccup data (vectors describing HTML) to process which may include references to components. -
local-components
: (Optional) A map of component configuration. Components defined here will overwrite components registered with->reg-component
for that function call only.
all-components
(all-components)
Lists all registered components (built in and user defined) and their associated metadata
clear-components
(clear-components)
Clears all components that where registered using ->reg-component
component->html
(component->html component-element-name)
(component->html component-element-name params)
(component->html component-element-name params local-components)
Generates and returns HTML of a component with the given component-element-name
.
Useful for generating the HTML of top-level web pages granted they are registered as component.
-
component-element-name
: The qualified keyword of the component element name. -
params
: (Optional) The params to pass to the component if it has parameters. -
local-components
: (Optional) A map of component configuration. Components defined here will overwrite components registered with->reg-component
for that function call only.
component->html-file
(component->html-file file-path component-element-name)
(component->html-file file-path component-element-name params)
(component->html-file file-path component-element-name params local-components)
Generates the HTML of a component with the given component-element-name
and saves the output to the given file-path
.
Useful for generating HTML files of top-level web pages granted they are registered as component.
-
file-path
: The file path to save the outputed HTML to. -
component-element-name
: The qualified keyword of the component element name. -
params
: (Optional) The params to pass to the component if it has parameters. -
local-components
: (Optional) A map of component configuration. Components defined here will overwrite components registered with->reg-component
for that function call only.
get-component-meta-data
(get-component-meta-data element-name)
Gets component metadata that was associated with the component when registered via reg-component
reg-component
(reg-component element-name component-meta-data component)
(reg-component element-name component)
Registers a component with the given element-name
(must be a qualified keyword e.g :my-components/login-form
) where the given component
can be either a pure function that returns Hiccup data, a vector (representing Hiccup data) or a string.
Once a component is registered it can be referenced in Hiccup data by its qualified keyword.
Supported parameters:
-
element-name
(Required): The element name (must be a qualified keyword e.g :my-components/login-form) that describes the component e.g.:ux.elements/ordered-list
,:ux.elements/unordered-list
. -
component-meta-data
(Optional): A clojure map representing metadata of the component. Should include the following keys:-
:doc
: A Docstring describing the component as well as its parameters. -
:example
: Hiccup data representing a single example of referencing the component. -
:examples
: Allows for providing multiple examples, should be a map with the key being the description of the example and the value being Hiccup data representing an example of referencing the component.
-
-
component
(Required): Can be either a pure function that returns Hiccup data, a vector (representing Hiccup data) or a string.
Example:
(hc/reg-component
;; Keyword to uniquely identify the component:
:ux.layouts/html-doc
;; Include meta data in the form of a map including `doc` and `examples` keys:
{:doc
"The main HTML document including a HEAD (with required CSS and Javascript
included) and BODY section.
This component is the basis for all top-level pages in the application.
The first parameter (a map) represents the component's options, followed by
a variable list of `child-elements` in the form of Hiccup data that will be
placed in the BODY.
Component options:
- `title`: The title of the HTML document (will populate the title tag
in the HEAD of the document)"
:examples {"With single child element"
[:ux.layouts/html-doc
{:title "One child element"}
[:div "Hello world"]]
"With multiple child elements"
[:ux.layouts/html-doc
{:title "Multiple child element"}
[:h1 "Hello world"]
[:p "This is a test"]
[:a {:href "/search"} "Try searching for more results"]]}}
;; Pure function implementing the responsibilities of the component:
(fn [{:keys [title] :as options} & child-elements]
[:html
[:head
[:meta {:charset "UTF-8"}]
[:meta {:content "width=device-width, initial-scale=1.0"
:name "viewport"}]
;; Include application CSS and any javascript
[:link {:rel "stylesheet" :href "/css/main.css"}]
[:script {:src "/js/app-bundle.js"}]
;; Include the title of the document
[:title title]]
;; Variable child elements included in body element
[:body child-elements]]))
user-defined-components
(user-defined-components)
Lists all user defined components and their associated metadata
wrap-response-middleware
(wrap-response-middleware request)
Ring middleware that will generate HTML using Hiccup server components conventions and set the :body
of the response to the generated HTML.
Works with Compojure and Reitit routing libraries as well as Ring compatible HTTP servers.
HTTP route handlers configured with this middleware can return a map including the following keys which will result in HTML being set on the response body:
-
:hsc/component
: The qualified keyword of the component to use to generate HTML that will be set as the:body
of the response. Component params can be supplied with the:hsc/params
key. -
:hsc/params
(Optional): Used in conjunction with the:hsc/component
key, represents params that will be passed to the component. -
:hsc/html
: Hiccup data (vectors describing HTML), that can include component references, that will be used to generate HTML that will be set as the:body
of the response.
Example of Compojure routes with middleware configured:
(ns http-routing.compojure
(:require [compojure.core :refer :all]
[ten-d-c.hiccup-server-components.core :as hc]))
(compojure.core/defroutes app
;; Generates and returns the HTML for the `:ux.pages/home` component, no
;; component params are provided.
(GET "/" []
{:hsc/component :ux.pages/home})
;; Generates and returns the HTML for the `:ux.pages/dashboard` component,
;; passing the component the `hsc/params` key as params.
(GET "/dashboard" []
{:hsc/component :ux.pages/dashboard
:hsc/params {:username "bobsmith"
:email-address "bobsmith@somemail.net"}})
;; Generates and returns the HTML from Hiccup data (which can include
;; component refererences) in the `:hsc/html` key.
(GET "/testing" []
{:hsc/html [:ux.layouts/html-doc {:title "A test page"}
[:div
[:h1.text-3xl "Hello world From HTML"]
[:p "This is a test"]]]}))
(def web-app (-> app
(hc/wrap-response-middleware)))
Example of Reitit routes with middleware configured:
(ns http-routing.reitit
(:require [reitit.ring :as ring]
[ten-d-c.hiccup-server-components.core :as hc]))
(def web-app
(ring/ring-handler
(ring/router
[["/" {:handler (fn [_]
{:hsc/component :ux.pages/home})}]
["/dashboard"
{:get
{:handler
(fn [_]
{:hsc/component :ux.pages/dashboard
:hsc/params {:username "bobsmith"
:email-address "bobsmith@somemail.net"}})}}]
["/testing"
{:get
{:handler
(fn [_]
{:hsc/html [:ux.layouts/html-doc {:title "A test page"}
[:div
[:h1.text-3xl "Hello world From HTML"]
[:p "This is a test"]]]})}}]]
{:data {:middleware [hc/wrap-response-middleware]
:enable true}})))