Request elements

The idea behind Hc is to allow any HTML element to perform requests on the server for HTML fragments. These requests are specified via the data-request attribute. We call request elements, elements that bear such an attribute.

In the following example:

<button data-request="POST /clicked"
        data-effect="element">Replace me</button>

The button is a request element. The request is performed when the event specified via the data-event attribute occurs. For buttons, if unspecified, this is the click event.

What happens exactly on a request is fully specified by the connection cycle which we describe next.

Connection cycle

Each request element defines a connection cycle in which a few other elements take part. All these other elements are always defined via attributes of the request element. They can all point to the same element. In particular if they are not specified they mostly default to the request element.

Every request element on the page cycle through the following steps.

  1. Wait for the element's request event to happen.
  2. Determine from the element's attributes, the kind of request, its query data, the target element, the effect and the feedback element(s).
  3. Perform the request with the query. Redirections are followed. The request and feedback elements get classified as hc-request
  4. Wait for the response. If an error occurs classify the request and feedback elements with hc-error and stop here. Otherwise unclassify hc-request and proceed.
  5. Process any special header in the response. This may stop the cycle here (e.g. on reload or redirect).
  6. Using the HTML fragment found in the server response, perform the effect on the target. If elements are being removed from the page, they first get classified with hc-out for a while before being effectively removed. Elements that are introduced get transiently classified with hc-in.
  7. If the request is:

    • a websocket, loop to 1 with the same socket.
    • SSE connection, loop to 4.
    • Otherwise loop to 1 (if the element still exists after the effect)

CSS class feedback

The following classes can be used to track the connection cycle.


This class is applied on the request element and the feedback element(s) whenever a request to the server is ongoing.

This class can be used to trigger a CSS animation if the request is taking too much time. For example assuming you have a .spinner in your request element, the following shows the spinner if the request is taking longer than 500ms.

.spinner { visibility: hidden; }
.hc-request .spinner { animation: spin 1s linear 500ms infinite; }

@keyframes spin
{ from { visibility: visible; } to { transform: rotate(360deg); }}


This class is applied on the request element and the feedback element whenever a request failed. This includes if the request returns a 4XX or 5XX result.

hc-in and hc-in-parent

These classes are applied for a small amount of time (one render frame) when the effect is performed. hc-in is applied on the root of HTML trees that are inserted in the DOM by the effect. hc-in-parent is applied on their parent.

These classes are used to trigger CSS animations. For example to fade in an element in 250ms on insertion use:

.my-element.hc-in { opacity: 0; }
.my-element { opacity: 1; transition: opacity 250ms; }

hc-out and hc-out-parent

These classes are applied on elements (if any) that are removed by the effect just before it is performed. hc-out is applied on elements that will be removed. hc-out-parent is on their parent.

To determine the amount of time during which the classes are applied before the effect is performed, first the classes are applied on the elements. Then for each of these elements we take the maximum value of either CSS attribute --hc-out-duration, animation-duration or transition-duration. The maximal value of all these durations defines the duration.

If the elements animating are descendent of those that are classified by hc-out or hc-out-parent, use the --hc-out-duration attribute on the .hc-out elements to set the time needed. For example the following ensures that the hc-out and hc-out-parent classes are maintained on the elements to be removed for 500ms before being effectively removed:

.hc-out { --hc-out-duration: 500ms }

Attribute reference

The only attribute required for an HTML element to be connected to your server is data-request which specifies the request to initiate the connection.

data-request="[<m>] <url>"

This attribute drives it all. If unspecified the element has no connection to the server and all other data-* attributes are ignored.

<url> is the URL to request, use the ws:// or wss:// scheme for a websocket connection. <m> is the HTTP request method or SSE to request a server sent events connection; defaults to GET if unspecified.


The value of <sel> determines the elements that are used to specify the query of the request. If unspecified this is the request element itself.

The final query of the request is determined by taking the query part of the requested URL and for each of the elements selected by <sel> appending:

The query is transmitted in the URL on GET or HEAD requests and otherwise in the request body encoded with application/x-www-form-urlencoded unless there is a file input in which case multipart/form-data is used.


Use this to prevent users from leaving a page without performing the request if the query data changed.

If true, the values determined by data-query are snapshot on DOM insertion. If they still exist and they changed when the beforeunload window event triggers the browser specific "leave page confirmation" modal is triggered.

data-event="<ev> <mod>*"

<ev> is the name of the JavaScript event of the event source that triggers requests. <mod> are modifiers for the event:

If the attribute is unspecified this is:


The DOM element(s), as selected by <sel>, whose events are being listened for to trigger a request. If unspecified this is the request element itself.


The target DOM element, as selected by the first element of <sel>, on which the request response performs its effect. If unspecified this is the request element itself.


The value <eff> determines the way the HTML response is used on the target. This can be:

If unspecified this is children.


DOM elements in addition to target element on which the connection cycle is feedback with hc-request and hc-error.

Selector syntax

Attributes of hc use CSS selectors with querySelector to gather query data and target response effects. However CSS selectors have no syntax for addressing ancestors. We slightly extend the syntax to allow it because in many cases this eschews the need to use element identifiers which improves modularity – use with care, it can also improve obscurity.

We allow a CSS selector to be prefixed by a sequence of ancestor specifications which select the root on which the CSS selector is then applied. This provides full tree addressing: first move up to find an ancestor and then down by applying the CSS selector to it.

An ancestor specification is made of an optional element, optional classes and the made up :up pseudo-class. The semantic is to move up from the element by following the up selectors from left-to-right and then apply the CSS selector on ancestor that was found.


  :up                # parent
  :up :up            # parent's parent
  :up :up :scope > * # parent's parent's children
  .beet.root:up      # ancestor with classes beet and root
  .beet:up .root:up  # move to beet ancestor, then to root ancestor
  ul.beet.root:up    # ul ancestor with classes beet and root
  div:up .beet       # div ancestor, beet classified descendents

The full syntax as an RFC 5234 ABNF grammar is described as follows:

         sel = *(up SP) css-selector
          up = [[el] *class] ":up"
          el = 1*(ALPHA)
       class = "." 1*(ALPHA)
css-selector = …   # See the CSS specification

Response HTTP headers

The server should respond with an HTML fragment to be inserted with respect to the request target. Additionally it can use the headers described next to control the client.

hc-redirect: <url>

Redirects the page to <url>. The body of the response is ignored by Hc.

hc-reload: true

Reloads the page. The body of the response is igored by Hc.

hc-location-push: <url>

Pushes location <url> on the history stack.

hc-location-replace: <url>

Replaces current location by <url> (without reloading). Has no effect if hc-location-push is present.

hc-location-title: <pct-title>

Replaces the current title by percent encoded title <pct-title>. Mostly used in conjunction with hc-location-push or hc-location-replace.

Request HTTP headers

hc: true

Indicates the request is made by Hc.

referer: <url>

This is the standard HTTP referer header, it indicates the URL of the page (without the fragment) that performs the request. hc makes requests with the same-origin policy.

If your HTML fragment returns relative URLs they will be interpreted relative to <url> once they are injected in the DOM.

FIXME. We should likely make that or at least the policy, tweakable in some way.