Sprig 1.1.0 adds Features & Security

November 23, 2020
by Ben Croker

Sprig 1.1.0 adds new features as well as some important security improvements. Most notably, Sprig now uses htmx 0.4.0 and adds template variables to paginate element queries, push URLs into the history stack, redirect and refresh the browser, trigger client-side events and more securely add values to a request.

Sprigcart preview

Changes #

The first thing you should know is that we have introduced a new, more secure way of adding values to a request. Up until now, adding the s‑vars attribute to a HTML element was the recommended way of passing values along with a request when that element triggered a re-render.

<button sprig s-vars="page: 2, limit: 10">Next</button>

The value passed in to the s-vars attribute is a comma-separated list of name-expression pairs. The expression parts (the numbers 2 and 10 above) are dynamically computed, meaning that if they contain JavaScript code then they will be executed. This feature is inherited from hx-vars and may make sense in some cases, but what it means is that if user input is used in the value, that it may result in a Cross-Site Scripting (XSS) vulnerability. 

{# If the `currentPage` variable contains user input then this component 
   may be vulnerable to a Cross-Site Scripting (XSS) attack. #}
<button sprig s-vars="page: {{ currentPage }}, limit: 10">Next</button>

For this reason, we have introduced two alternative attributes, s‑vals and s‑val:*. s-vals takes a list of name-value pairs in JSON format and does not execute any code so is safer to use. 

{# Note how we use the `json_encode` filter to format the values correctly. #}
<button sprig s-vals="{{ {page: currentPage, limit: 10 }|json_encode }}">Next</button>

{# Outputs the same as above. #}
{% set values = { 
    page: currentPage, 
    limit: 10,
} %}
<button sprig s-vals="{{ values|json_encode }}'">Next</button>

The s-val:* attribute provides a more readable way of populating the s-vals attribute. Replace the * with a lower-case name (in kebab-case, dashes will be removed and the name will be converted to camelCase).

{# This is the recommended way to add values to a request. #}
<button sprig s-val:page="{{ currentPage }}" s-val:limit="{{ 10 }}">Next</button>

The s-vars attribute has been deprecated. While it will continue to work, we highly recommend replacing it in your code with the new s-vals or s-val:* attribute. If you absolutely require the functionality that s-vars provides then use hx-vars directly.

New Features #

Attributes #

s‑replace replaces only the specified element in the component. This is useful if you want to only re-render part of a component, such as search results, but not the search input field itself. 

{# Replaces only the element with ID `results`. #}
<input sprig s-replace="#results" type="text" name="query">

<div id="results"></div>

s-replace is inherited and can be placed on any parent element of the element that triggers a re-render.

Template Variables #

Script Tags #

You can now place <script> tags inside of your Sprig components that will be run when a component is re-rendered.

{# Take the usual precaution of never outputting user input inside of `script` tags. #}
    console.log('Blimey, I can run code here.');

Removals #

The following undocumented magic variables have been removed, which allowed us to reduce complexity in the codebase.

  • _url has been removed, use the new sprig.pushUrl() function instead.
  • _events has been removed, use the new sprig.triggerEvents() function instead.

One More Thing #

This release of Sprig adds some incredibly useful features that have been on our wishlist for a while. More importantly, it allows us to create some novel components that we are going to be sharing in the coming weeks. Here’s a sneak peek.

Sprigcart preview