Geertjan's Blog

  • June 8, 2015

From Responsive CSS to Responsive JavaScript with Foundation.js & Knockout.js

Geertjan Wielenga
Product Manager

Whereas Response.js, discussed in the previous blog entry, is handy for modifying the DOM by swapping out DOM elements (instead of using CSS rules to hide DOM elements) based on screen size, an alternative approach, focused on HTML fragments, is provided by Foundation.js, in particular, Foundation Interchange.

Foundation is a UI framework, comparable to Twitter Bootstrap and Angular UI. In the 5.0 release of Foundation, Interchange was made available. Interchange is responsive JavaScript, allowing you to do powerful stuff on the client side, within the HTML view of your application:

<div data-interchange="
[fragments/small.html, (small)],
[fragments/medium.html, (medium)],
[fragments/large.html, (large)]">

Below, you can see that I have a folder named "fragments", in which I have the HTML files referenced above. The div above is found, in this example, in the "index.html", which you can see is relative to the "fragments" folder. Thanks to the above code, automatically, when the screen size changes, Foundation Interchange loads the appropriate fragment.

For this example, each of the fragments contain content like this, here for the "small.html":

<b>You're using a small resolution.</b>

Just like with Response.js, and unlike CSS rules, nothing is hidden. Instead, files are loaded or not loaded, depending on the size of the screen. In the first screenshot below, you can see in the Network Monitor that the "small.html" is loaded, while none of the other fragments are loaded, simply because the screen size has changed and Foundation Interchange has picked that up and unloaded the fragments that may have been loaded before, while loading the new fragment appropriate to the current screen size:

In the next example, there's a different screen size, and so as you can see Foundation Interchange has now loaded "medium.html", while no other fragments have been loaded and those that were loaded before have been unloaded:

If you were using Google Maps in your application and assuming you didn't want to include that for small devices, you'd simply not have the Google Maps code in the "small.html". That would mean that none of the Google Maps libraries would be loaded for small devices, since for small devices you're loading the "small.html".

How to set up Foundation Interchange? Start by including Foundation in your Bower file, as shown below:

"dependencies": {
"knockout": "3.3.0",
"requirejs-text": "2.0.14",
"requirejs": "2.1.17",
"bootstrap-dropdown": "*",
"jquery": "2.1.4",
"responsejs": "0.9.1",
"foundation": "5.5.2"

Then, in the 'main.js', which is highlighted in the first screenshot in this blog entry, (in this case, I'm referring to Solid Knockout, where all the code in this blog entry is included), add the changes shown in bold below to set up and initialize Foundation:

baseUrl: './',
paths: {
knockout: './js/libraries/knockout/dist/knockout',
text: './js/libraries/requirejs-text/text',
jquery: './js/libraries/jquery/dist/jquery',
response: './js/libraries/responsejs/response',foundation: './js/libraries/foundation/js/foundation',
initComponents: './js/initComponents'
// Shim configuration for modules that do not expose AMD:
shim : {
deps: ['jquery']
}, 'foundation':{
deps: ['jquery']

waitSeconds: 2
require(['knockout', 'initComponents', 'response', 'foundation'],
function (ko, initComponents) {$(document).foundation();
var self = this;
self.weAreSmall = ko.observable();
breakpoints: [0, 480, 481]
Response.action(function() {
if (Response.band(0, 480)){
} else {
ko.applyBindings(new initComponents());

After you've done the above, use "data-interchange" in a div element, exactly as shown at the start of this blog entry.

As in the previous blog entry, I'm indebted to my colleague JB Brock for the code and explanation above, which you can follow on YouTube here, from about the 24th minute. All the code above is incorporated into Solid Knockout.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.