DEV Community

bretgeek
bretgeek

Posted on

Surf JS - An Insanely Small JavaScript UI Library With Reactive Element Templates and JQuery Alternative

Surf JS

What is it?

It's an insanely small ~13kb minified (that's ~2.6kb smaller than cash @ https://github.com/fabiospampinato/cash ), plugin extendable JavaScript library for building user interfaces (UI).

Surf JS is a few different things all wrapped up in one small package.

But it's also a super small JQuery clone/replacement library that has reactive element templates (read on to learn what these are).

Don't let the JQuery clone part fool you! - Surf JS lets you build your component based UI using a familiar syntax and NO JSX! Using Surf JS as you would JQuery (in a non component based way) is entirely optional!

Surf JS doesn't implement all JQuery methods but the basics are pretty similar and you can always configure Surf JS to do anything you want via plugins.

A good way to think about Surf JS is that it's like JQuery if JQuery had a way to use components AND if JQuery had reactive element templates...with a much smaller footprint than JQuery.

If you would rather not think about it, you could just use Surf JS as a replacement for JQuery!

Where To Get It?

Get it from Github: https://github.com/bretgeek/surf/

Visit: https://surf.monster for more documentation, updates and working examples.

Features

  • Super Small! - currently at around ~13KB minified (smaller if gzipped).

  • Reactive Element Templates - Reactive element templates are strings in your HTML that look like {{msg}} and once initialized can become ANYTHING you desire when you desire. When your data changes you can set the template to your new data, new HTML or even new components!

  • Lightweight JQuery Clone - Can be used as a general purpose JQuery like library.

  • Easy Familiar Syntax - familiar chainable syntax with built-in DOM manipulation methods.

  • Build with Components - Optional component based syntax allowing you to build your UI with re-usable components without using JSX as well as solving CSS bleed issues from web components.

  • Extendable - Highly configurable (you can change anything you want about the base functionality with a run time config) and it's extendable with plugins.

  • Versatile - It's intended to give you power and not lock you down into any one way of doing things. You can probably find ways to use it that the author has not even thought of yet. Use it in ways that you and your team define!

Getting Started

Basic usage for manually adding and using Surf JS to a web page.

Add Surf JS to your page before your closing body tag:



<script src='https://yoururl.com/surf.min.js'></script>



Enter fullscreen mode Exit fullscreen mode

First make sure it works

So we can do more interesting things later but first let's use Surf JS similar to how we would use JQuery to make sure our setup is working.

In an html file:


// Somewhere in your HTML

<div id='app'> I am an App </div>


Enter fullscreen mode Exit fullscreen mode

In a script tag after surf.min.js:


// Create kickoff function that will run once the document is ready.

function kickoff(){

// There are many options to "grab" but this minimal use returns the first element of #app by default

$('#app').css('color: red;');

}


// Run your function when the document is ready...

$(document).ready(kickoff);


Enter fullscreen mode Exit fullscreen mode

You should now see "I am an App" in red.

Reactive Element Templates

Surf JS has a really powerful feature called "Reactive Element Templates" that allows you to manipulate your HTML with changing data defined by {{templates}} . Since Reactive Templates resolve to functions (once they are activated) there is no DOM querying...changes are live!
The main takeaway here is that...when your data changes, templates can be used to display your data as text, HTML or even components!

Lets start with a basic example to see how Reactive Templates work

In your html file add:


// Somewhere in your HTML

<div id='msgapp'> This is a {{msg}} </div>


Enter fullscreen mode Exit fullscreen mode

In your script file somewhere in your kickoff function add:


// Somewhere in your kickoff function of your JS script

// Use set to change msg and CSS to color #msgapp green so we can see it;

$('#msgapp').set({msg: ' my narly note!'}); // We can send in HTML, text or components here;
$('#msgapp').css('color: green;');


Enter fullscreen mode Exit fullscreen mode

If you are lucky enough to catch a glimpse you should see the msg in the template change when the browser is done loading.
Keep in mind this is setting the templates via HTML in a textual based JQuery like way, but templates give you even more power when setting them to or from components!

Components

Creating a re-usable component is as easy as writing a function (a named function or an arrow function and a name parameter) that returns an element then registering it by calling a special function $().register(componentName) to register it. Once registered it can be used over and over by it's name.

Let's give it a try:

First we will need a place to put our component in.

In your HTML file:


// Somewhere in your HTML

<div id='comp1'> COMPONENT  </div>



Enter fullscreen mode Exit fullscreen mode

Now lets make the component - a button that increments a counter when clicked.

Somewhere in your kickoff script file (or where it will be called by ready) define a function for your component:



// A button component that counts when clicked

function buttonCounter(props={}){ // You can also pass in a props object 
let color = props.color || 'green';

   // The component with create a node each time it's used

   const node = $().createNode('button');


   // This node's CSS, attributes, reactive template and html

   $(node).html('Count is: {{cnt}} ').attr('data-count', 0).css('cursor: pointer;').css(`color: ${color};`); // color from props


   // initialize cnt template to 0

   $(node).set({cnt: '0'});

// Add a click event to the node
$(node).on('click', function(){
let cnt = parseFloat($(this).attr('data-count'))+1;
$(this).attr('data-count', cnt);
$(this).set({cnt: cnt});
});


 // A component must return an element
return node;
}



// Register the component
$().register(buttonCounter); 


Enter fullscreen mode Exit fullscreen mode

To make sure our component works we will use Surf JS's "append" method to add it to the DOM... but keep in mind you can add components to other components with a special syntax which we will get to later.



// create a reference to a component

const abutton = $().buttonCounter(); // pass in option props too


// Create a reference to the place we want to put our component

const comp1 = $('#comp1').first();


// Finally append the component to the element in DOM

$(comp1).append(abutton);  // OR without a reference: $(comp1).append($().buttonCounter());


Enter fullscreen mode Exit fullscreen mode

You should now see a clickable button with a counter that increments as you click.

Syntax to render components to other components

The most useful thing about components is their re-use. In this section we will go over how to add a component to another component.
Here we will make a containerBox component and add our buttonCounter we made earlier to it. We will add buttonCounter twice to show different ways to do it.

Make a place to in the DOM to hold our containerbox component.

In your HTML file add:


// Somewhere in your HTML

<div id='comp2'> some random place holder text not required  </div>


Enter fullscreen mode Exit fullscreen mode

In your kickoff script file add the code below for the containerBox component:


// A component for a container box

function containerBox(){

  // The kind of element this component will be...

  const node = $().createNode('div');

  // Some HTML with a reactive template for demonstration purposes.

  $(node).html('{{ button }} ')


  // Some CSS to add a border so we can see it.

  $(node).css('border: 2px solid blue; padding: 9px; width: 120px;'); 


  // There are two ways to add a component - use the Set method on templates or DOM insertion.
  // If using both ways in the same component the Set method on templates must come first.


  // First way: Set a template to another component

  $(node).set({ button: $().buttonCounter() });


  // Second way: Use DOM manipulation methods to add a component to this component

  $(node).prepend( $().buttonCounter() );

  return node; // compontents must return an element
}

// Don't forget to register it somewhere in your script file
$().register(containerBox);



Enter fullscreen mode Exit fullscreen mode

Test it to see if adding components to another works.

Somewhere else in your kickoff script add:



const abox = $().containerBox(); // create a new instance  

$('#comp2').append(abox); // add to somewhere in the DOM OR with variable instance do $('#comp2').append($().containerBox());



Enter fullscreen mode Exit fullscreen mode

You should now see three components - 1 containerBox component containing 2 buttonCounter components!

We covered a lot of ground introducing the basics of Surf JS but the possibilities are endless!

I hope you have enjoyed this short tutorial on getting started with Surf JS and would love to read your comments and see what you will build.

If you found this interesting please favorite here and star Surf JS project on Github https://github.com/bretgeek/surf/

Top comments (3)

Collapse
 
bretgeek profile image
bretgeek • Edited

No need to be negative guys, It's about having options not opinions.

P.S. D3 JS has a JQuery like syntax, it's useful:)

Collapse
 
loucyx profile image
Lou Cyx

We have already great modern alternatives to the jQuery style like Alpine.js, and if you don't like that, you can get a React-like app with little to no setup using preact with htm (both libraries are extremally small).

Is your library, so is up to you, but I'll suggest that you consider that folks using jQuery in 2022, will keep using it no matter what, and the rest of us don't want to use something similar to it, so being on your shoes I would make the API less "jQuery like" so maybe it becomes more compelling for devs.

Cheers!

Collapse
 
zodman profile image
Andres 🐍 in 🇨🇦

that feels to 90's