Blazing fast Apple TV application development using pure JavaScript

Overview

atvjs

Join the chat at https://gitter.im/atvjs/Lobby

Blazing fast Apple TV application development using pure JavaScript.

Philosophy

What?

This is a super simple framework for blazing fast Apple TV application development using pure JavaScript. It relies on the tvOS provided TVML and TVJS for Apple TV development. However this framework does most of the heavy lifting for you and lets you concentrate on your application logic without worrying about the hassles of complicated architecture for Apple TV development. Build your Apple TV application the same way how you are used to building your SPA applications in JavaScript and let the framework handle the rest for you.

Why?

The existing application architecture and sample code provided by apple for building the Apple TV applications using TVML and TVJS appears to be very immature (no offense Apple) and feels more like the web applications of the 90s where each of the page loads separately by sending the request to the back-end which generates your application page markup based on the user interaction and sends the new page back to the browser. This is okay if we were still in the 90s but feels so dumb in this era where we are used to building SPAs with REST APIs and back-end is used just as a data interaction point. Here comes atvjs that bridges the gap and lets you use the same architecture that, we as front-end developers, have embraced over the years.

How?

You simply create your pages (views) by passing a bunch of configurations (name of the page, template function, url etc) with your desired data (you can either populate data manually using your own ajax requests or pass a url configuration to fetch data from your server). Once the page is created, it is uniquely identifiable using the name. You can navigate to your page anytime in your application using the same name.

What's included

  • Page, Menu and Modal Creation and Navigation ATV.Page.create, ATV.Menu.create, ATV.Navigation.navigate, ATV.Navigation.navigateToMenuPage, ATV.Navigation.presentModal
  • TVML styling capabilities (both global as well as individual page level)
  • Event handling (both global and for individual pages and elements)
  • Application level persistent data storage using localStorage with lz-string compression ATV.Settings.set, ATV.Settings.get, ATV.Settings.remove
  • Ajax library using JavaScript Promises ATV.Ajax, ATV.Ajax.get, ATV.Ajax.post, ATV.Ajax.put, ATV.Ajax.del
  • Application level publish/subscribe using PubSubJS ATV.subscribe, ATV.publish, ATV.unsubscribe
  • Application initialization/reload using simple configurations ATV.start, ATV.reload
  • Global error handling
  • JavaScript Promise and other ES6 Features Polyfill using babel
  • lodash library as ATV._

Getting Started

atvjs is defined as a UMD and available as an npm package. You can either import it as a dependency or download it independently and include in your project.

$ npm install --save atvjs

You'll then be able to use it as a dependency with your favorite module system.

import ATV from 'atvjs';
// or
var ATV = require('atvjs');

Or if you have downloaded a copy of atvjs, pull the script inside your application after launch.

function onEvaluate(success) {
	if (!success) {
		// application failed to load
	}
}

App.onLaunch = function(options) {
	var baseurl = options.BASEURL;
	App.launchOptions = options;
	evaluateScripts([`${baseurl}atv.min.js`, `${baseurl}app.js`], onEvaluate);
};

// then in your app.js you will have the instance of ATV library available
// you can contain your entire application code inside app.js

Basic Examples

Creating Pages

Create pages in your application using the page factory. You will then be able to navigate to these pages using the name of the page.

ATV.Page.create({
	name: 'home',
	// use a template function from your favourite templating engine
	// or pass a raw template function
	template(data) {
		return `<document>
					<alertTemplate>
						<title>${data.title}</title>
						<description>${data.description}</description>
					</alertTemplate>
				</document>`;
	},
	// pass some raw data to be applied
	// or a data function that returns the data
	data: {
		title: 'Homepage',
		description: 'This is my super awesome homepage created using atvjs.'
	}
});

// later in your application you can do something like below to navigate to the page
ATV.Navigation.navigate('home');

Adding TVML styles to your page

You need to define your TVML styles as string and pass that as a configuration to your page. It will automatically be added to your page document in the runtime when your page is being navigated.

let myPageStyles = `
.text-bold {
	font-weight: bold;
}
.text-white {
	color: rgb(255, 255, 255);
}
`;

ATV.Page.create({
	name: 'home',
	style: myPageStyles,
	template: your_template_function,
	data: your_data
});

Fetching data from a remote source

You can fetch JSON content from the remote api by setting the url configuration. The data will be fetched using ajax and will be applied to the provided template. You can even run some transformations on the data before applying it to the template

ATV.Page.create({
	name: 'home',
	url: 'path/to/your/api/that/returns/json',
	template: your_template_function
});

// or you can transform the response before applying to your template
ATV.Page.create({
	name: 'home',
	url: 'path/to/your/api/that/returns/json',
	template: your_template_function,
	data(response) {
		// transform your response before applying to your template
		let transformedData = someTransformationOfResponse(response);
		return transformedData;
	}
});

Creating links to other pages

You can setup links to other pages directly in your TVML markup by setting the data-href-page attribute with the value of your page name that you want to link to. The framework will take care of the navigation for you. You can also pass options to your page (see topic Custom options while navigation for details) by setting up the data-href-page-options attribute with a JSON value.

<document>
	<alertTemplate>
		<title>Example for creating links to other pages</title>
		<description>Select an option</description>
		<button data-href-page="homepage">
			<text>Go To Homepage</text>
		</button>
		<button data-href-page="login" data-href-page-options='{"username": "emadalam", "password": "123456"}'>
			<text>Login</text>
		</button>
	</alertTemplate>
</document>

Advanced Topics

Event Handling

You can define the list of events and their respective handlers as key-value pairs. The handler will be invoked in the current object context and you can access all the methods and properties that exist on the object.

ATV.Page.create({
	name: 'mypage',
	template: your_template_function,
	data: your_data,
	events: {
		select: 'onSelect',
		highlight: 'onHighlight'
	},
	// method invoked in the scope of the current object and
	// 'this' will be bound to the object at runtime
	// so you can easily access methods and properties and even modify them at runtime
	onSelect(e) {
		let element = e.target;
		let someCheckForElementType = element.getAttribute('data-my-attribute');
		let someOtherCheckForElementType = element.getAttribute('data-my-other-attribute');

		if (someCheckForElementType) {
			this.doSomethingOnElementType1();
		}

		if (someOtherCheckForElementType) {
			this.doSomethingOnElementType2();
		}
	},
	onHighlight(e) {
		// same as above
	},
	doSomethingOnElementType1() {
		// some awesome action
	},
	doSomethingOnElementType2() {
		// some other awesome action
	}
});

Custom options while navigation

You can pass your application state/logic to make reusable dynamic pages that renders a new page each time the navigation is performed. This can be achieved by setting a ready method in the configuration that accepts 3 parameters, options, resolve and reject. These parameters are automatically passed to the ready method whenever a navigation to this page is performed. The navigation relies on JavaScript Promises, so you'll have to call resolve/reject method after performing your logic.

ATV.Page.create({
	name: 'login',
	template: your_template_function,
	// the ready method is called each time the navigation to this page is performed and
	// the options object is passed to the method at runtime
	// use options to pass any dynamic state of your application
	// you can then use this state and populate your data (either using custom ajax or some other logic)
	// once the data is populated, call the resolve method with the data or reject method for failure
	ready(options, resolve, reject) {
		let data = {
			username: options.username,
			password: options.password
		};
		// perform ajax to get the data
		// the ajax method in the library returns an instance of the Promise object
		ATV
			.Ajax
			.post('someURL', {data: data})
			.then((xhr) => {
				// xhr succeeded
				let response = xhr.response;
				// call resolve with the data that will be applied to the template
				// you can even call resolve with false to skip navigation
				resolve({
					name: response.name,
					message: response.message
				});
			}, (xhr) => {
				// xhr failed
				let response = xhr.response;
				reject({
					status: xhr.status,
					message: response.message
				});
			});
	}
});
// later in your application
ATV.Navigation.navigate('login', {username: 'emadalam', password: '123456'});

Creating Menu Page

The way menu template is designed in TVJS, you need to first create a menu template with your list of menu items. You then need to create individual documents and set one for each of the menu item. The resultant menu template then needs to be parsed and converted into a document which you can push on the navigation stack. Sounds fancy? NO WAYS! Here comes atvjs for your rescue. All you need is a menu configuration with your items list and the pages that you want to associate. The rest will be taken care by the framework. You can then navigate to the menu page using the provided navigation method. SWEET!

Note: Menu page is singleton, meaning you cannot create multiple menu pages. It seems logical, as an application at any given state, will have a single menu listing in its entire lifespan.

// create your pages
let SearchPage = ATV.Page.create({/* page configurations */});
let HomePage = ATV.Page.create({/* page configurations */});
let MoviesPage = ATV.Page.create({/* page configurations */});
let TVShowsPage = ATV.Page.create({/* page configurations */});

// create menu page
ATV.Menu.create({
	// any attributes that you want to set on the menuBar element of TVML
	attributes: {},
	// any attributes that you want to set on the root level menuBarTemplate element of TVML
	rootTemplateAttributes {},
	// array of menu item configurations
	items: [{
		id: 'search',
		name: 'Search',
		page: SearchPage
	}, {
		id: 'homepage',
		name: 'Home',
		page: HomePage,
		attributes: {
			autoHighlight: true, // auto highlight on navigate
			reloadOnSelect: true // reloads page when selecting it, instead of loading from cache
		}
	}, {
		id: 'movies',
		name: 'Movies',
		page: MoviesPage
	}, {
		id: 'tvshows',
		name: 'TV Shows',
		page: TVShowsPage
	}]
});

// later in your application
ATV.Navigation.navigateToMenuPage();

Application initialization using configuration

You can easily initialize your application by passing all the configurations at once.

// create your pages
let SearchPage = ATV.Page.create({/* page configurations */});
let HomePage = ATV.Page.create({/* page configurations */});
let MoviesPage = ATV.Page.create({/* page configurations */});
let TVShowsPage = ATV.Page.create({/* page configurations */});
let LoginPage = ATV.Page.create({/* page configurations */});

// template functions
const loaderTpl = (data) => `<document>
	<loadingTemplate>
		<activityIndicator>
			<title>${data.message}</title>
		</activityIndicator>
	</loadingTemplate>
</document>`;

const errorTpl = (data) => `<document>
	<descriptiveAlertTemplate>
		<title>${data.title}</title>
		<description>${data.message}</description>
	</descriptiveAlertTemplate>
</document>`;

// Global TVML styles
let globalStyles = `
.text-bold {
	font-weight: bold;
}
.text-white {
	color: rgb(255, 255, 255);
}
.dark-background-color {
	background-color: #091a2a;
}
.button {
	background-color: rgba(0, 0, 0, 0.1);
	tv-tint-color: rgba(0, 0, 0, 0.1);
}
`;

// start your application by passing configurations
ATV.start({
	style: globalStyles,
	menu: {
		attributes: {},
		items: [{
			id: 'search',
			name: 'Search',
			page: SearchPage
		}, {
			id: 'homepage',
			name: 'Home',
			page: HomePage,
			attributes: {
				autoHighlight: true // auto highlight on navigate
			}
		}, {
			id: 'movies',
			name: 'Movies',
			page: MoviesPage
		}, {
			id: 'tvshows',
			name: 'TV Shows',
			page: TVShowsPage
		}]
	},
	templates: {
		// loader template
		loader: loaderTpl,
		// global error template
		error: errorTpl,
		// xhr status based error messages
		status: {
			'404': () => errorTpl({
				title: '404',
				message: 'The given page was not found'
			}),
			'500': () => errorTpl({
				title: '500',
				message: 'An unknown error occurred, please try again later!'
			})
		}
	},
	// global event handlers that will be called for each of the pages
	handlers: {
		select: {
			globalSelecthandler(e) {
				let element = e.target;
				let someElementTypeCheck = element.getAttribute('data-my-attribute');

				if (elementTypeCheck) {
					// perform action
				}
			}
		}
	},
	onLaunch(options) {
		// navigate to menu page
		ATV.Navigation.navigateToMenuPage();
		// or you can navigate to previously created page
		// ATV.Navigation.navigate('login');
	}
});

Sample Code

Useful Links

Contributions

  • Fork the project
  • Commit your enhancements and bug fixes
  • Create a pull request describing the changes

License

atvjs is released under the MIT License.

Comments
  • Support menu item reload configuration

    Support menu item reload configuration

    Currently

    Selecting the menu item loads the previously loaded cached page and there is no way to force reload it based on configuration.

    Wanted

    Support attribute configuration reloadOnSelect to load a non-cached version of the page on every selection.

    ...
    menu: {
        items: [{
            ...
            attributes: {
                reloadOnSelect: true
            }
        }]
    }
    ...
    
    enhancement 
    opened by emadalam 13
  • Need help, newbie here

    Need help, newbie here

    I am trying to develop an application using atvjs; installed node and npm; installed packages and so on. If in my app.js I do "import atvjs" is not working; also if I do "var atvjs = require('atvjs') is not working and I get "ReferenceError: Can't find variable: require"

    Where am I wrong?

    opened by MarcoGT 7
  • Navigation.showError() modals are unable to be dismissed

    Navigation.showError() modals are unable to be dismissed

    Modal dialogs created with navigationDocument.presentModal() are able to be dismissed but using Navigation.showError() results in a dialog where the button does not work, escape or home must be used to dismiss.

    Consider the following code if added to the Movie Catalog example app in the ready method of the HomePage object:

    const showError = () => {
      // const alert = `<?xml version="1.0" encoding="UTF-8" ?>
      //     <document>
      //       <alertTemplate>
      //         <title>Error</title>
      //         <description>This modal cannot be dismissed.</description>
      //         <button data-alert-dissmiss="close">
      //           <text>OK</text>
      //         </button>
      //       </alertTemplate>
      //     </document>`;
      // const error = ATV.Navigation.showError({ template: alert, style: '' });
    
      const alert = `<?xml version="1.0" encoding="UTF-8" ?>
        <document>
          <alertTemplate>
            <title>Error</title>
            <description>This modal can be dismissed.</description>
            <button>
              <text>OK</text>
            </button>
          </alertTemplate>
        </document>`;
      const parser = new DOMParser();
      const error = parser.parseFromString(alert, 'application/xml');
      navigationDocument.presentModal(error);
    
      error.addEventListener('select', () => {
        ATV.Navigation.dismissModal();
      })
    };
    

    The uncommented version works as expected. Inverting the commented code results in the modal not being dismissed but with the data-alert-dissmiss [sic] attribute the navigationDocument.dismissModal() method is called, as indicated by the log: close button clicked within the modal, dismissing modal...

    opened by dnicolson 6
  • Refreshing app

    Refreshing app

    @emadalam this isn't an issue so much as a question - How would you go about refreshing the UI when you need new data to populate? For example, if you have a movie listing page, periodically the list of movies changes. I'd like to cause the UI to refresh periodically. Thanks in advance ๐Ÿ˜„

    question 
    opened by tortillaj 4
  • Fetching data and display it

    Fetching data and display it

    Hello,

    I would like to fetch json and display it on template.

    I use :

    ATV.Page.create({
        name: 'home',
        url: 'http://www.example.com/data.json',
        template: template
    });
    

    data.json :

    {
        "CATALOG": {
            "ITEM": [{
                "TITLE": "Title 1"
            }, {
                "TITLE": "Title 2"
            }, {
                "TITLE": "Title 3"
            }]
        }
    }
    

    in template.hbs, I use :

    ... <title>{{ CATALOG.ITEM[0].TITLE }}</title> ...
    

    But I have error launching application. How do I do to get the first title ?

    opened by procom 4
  • Updating dependencies

    Updating dependencies

    Hi, nothing exciting with new features, but I updated bundled lodash and pubsub-js, so users dont have to load another lodash if they need it and the atvjs package wont show any vulnerabilites in github.

    opened by MarhyCZ 3
  • Ajax should utilize more complete promise

    Ajax should utilize more complete promise

    I find it confusing and limiting when the Ajax call returns a promise but doesn't utilize the reject capability.

    So instead of handling success/failure in the resolved promise (the then()):

    ATV
    			.Ajax
    			.post('someURL', {data: data})
    			.then((xhr) => {
    				// xhr succeeded
    			}, (xhr) => {
    				// xhr failed
    			});
    

    You would have more true promise-based logic using then() and/or catch() and/or finally():

    ATV
    			.Ajax
    			.post('someURL', {data: data})
    			.then((xhr) => {
    				// xhr succeeded
    			})
    			.catch((xhr) => {
    				// xhr failed
    			})
    			.finally(() => {
    				// regardless of success/failure, also do this
    			});
    

    For developers who understand promises, the current implementation seems halfway done. It also prevents normal promise chaining, which flattens out the old "callback hell" problem.

    opened by DavidFrahm 3
  • Pages not regenerating

    Pages not regenerating

    Came across this comment on SO indicating that pages would regenerate when you navigate to them.

    This doesn't seem to be the case for me at the moment, are changes to the template supposed to be available without rebooting the application?

    invalid wontfix 
    opened by hamishtaplin 3
  • Attributes for menuBarTemplate

    Attributes for menuBarTemplate

    Hi, it's a very small commit which adds option to set attributes onto the menuBarTemplate tag. Thanks to this, I was able to set theme: 'dark' attribute. darkmenu lightmenu

    opened by MarhyCZ 2
  • Pass options to page and display it

    Pass options to page and display it

    Hello,

    I would like to pass options to a page with data-href-page-options. <button data-href-page="details-page" data-href-page-options='{"title": "Hello World"}'>

    /details-page/index.js :

    ATV.Page.create({
        name: 'DetailsPage',
        template: template,
        WHAT CODE TO RETRIEVE OPTIONS ?
    });
    

    /details-page/template.hbs :

    <document>
      <productTemplate>
        <banner>
          <stack>
            <title>WHAT CODE TO DISPLAY OPTIONS</title>
          </stack>
        </banner>
      </productTemplate>
    </document>
    

    Thanks.

    question 
    opened by procom 2
  • DOMParser is not defined

    DOMParser is not defined

    Hey. First, thanks for your work. I think, that this project can be very useful, but I got the following problem.

    I've created an index.js file with the following content, based on your example code.

    var ATV = require('atvjs');
    
    ATV.Page.create({
        name: 'home',
        // use a template function from your favourite templating engine
        // or pass a raw template function
        template(data) {
            return `<document>
                        <alertTemplate>
                            <title>${data.title}</title>
                            <description>${data.description}</description>
                        </alertTemplate>
                    </document>`;
        },
        // pass some raw data to be applied
        // or a data function that returns the data
        data: {
            title: 'Homepage',
            description: 'This is my super awesome homepage created using atvjs.'
        }
    });
    
    // later in your application you can do something like below to navigate to the page
    ATV.Navigation.navigate('home');
    

    I'm using Node.js 4.4.0. And the following error ist the result of that.

    /srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:18710
        var parser = new DOMParser(); // native DOM parser
                         ^
    
    ReferenceError: DOMParser is not defined
        at Object._typeof (/srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:18710:19)
        at __webpack_require__ (/srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:34:30)
        at Object.<anonymous> (/srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:77:16)
        at __webpack_require__ (/srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:34:30)
        at /srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:54:18
        at /srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:57:10
        at webpackUniversalModuleDefinition (/srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:7:20)
        at Object.<anonymous> (/srv/www/SUB.DOMAIN.TLD/www/node_modules/atvjs/dist/atv.js:14:3)
        at Module._compile (module.js:435:26)
        at Object.Module._extensions..js (module.js:442:10)
    

    Do you have any idea how this can be fixed?

    Thanks.

    invalid 
    opened by teawithfruit 2
  • Question about best practice: how to automatically play next?

    Question about best practice: how to automatically play next?

    Any thoughts on how to best implement "automatically play next", when at the end of one episode, the player will automatically pick up the next one?

    question 
    opened by hfedak 2
  • Dark loading indicator page

    Dark loading indicator page

    I have an app that uses a MenuBar template with items set with reloadOnSelect. Every time I change view it reloads the content from an API and the loading indicator shows up. Each view has a dark theme but when the loading indicator shows, the background is bright.

    Is it possible to set a dark background when the loader shows?

    I thought of setting a class to the element and use CSS but it does not work either.

    question 
    opened by quochuy 4
  • presentModal closes itself on first use

    presentModal closes itself on first use

    When ATV.Navigation.presentModal(descriptiveAlertTemplateString) is called the modal opens, but on the first time it closes itself right away. It seems fine on the calls after that. Might this be a bug?

    opened by smakinson 0
  • Reload a Page with AJAX Content

    Reload a Page with AJAX Content

    I'm actually writing a private TVML/TVJS-App with atvjs. First thanks for your brilliant framework-work!

    I've got one problem: I've got an interactive HomePage and also interactive subpages. So at the start of the app the app gets the JSON from the server and render it to the template. This page is cached then and can not be re-rendered; or?

    For example: I've got a page with a list of TV-Show episodes, on these episodes I've got a marker for the "Last seen"-episode. When I watch an episode the JS-File of the player then tells the server that the episode is watched. After exiting the player, the list should be dynamically re-rendered to display the newest server-information.

    Is there a way to make boundings between ajax/template to re-render pages dynamically?

    Thanks a lot!

    opened by hajanet 5
  • Promises reworked, menubar functionality in events/options improved

    Promises reworked, menubar functionality in events/options improved

    1. Promises significantly improved;
    2. ready/afterready events converted to promises;
    3. options parameters for menu page invocation;
    4. babel polyfill already exists check added
    5. custom menu template option
    opened by shoshins 0
:fire: An extremely fast, React-like JavaScript library for building modern user interfaces

Inferno is an insanely fast, React-like library for building high-performance user interfaces on both the client and server. Description The main obje

Inferno 15.6k Jan 3, 2023
HTML5 application architecture using Backbone.js

An Application Architecture Using Backbone.js Introduction Chaplin is an architecture for JavaScript applications using the Backbone.js library. All i

Chaplin โ€“ JavaScript Application Architecture Using Backbone.js 2.9k Jan 4, 2023
An HTML5/CSS3 framework used at SAPO for fast and efficient website design and prototyping

Welcome to Ink Ink is an interface kit for quick development of web interfaces, simple to use and expand on. It uses a combination of HTML, CSS and Ja

SAPO 1.9k Dec 15, 2022
โš›๏ธ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.

Fast 3kB alternative to React with the same modern API. All the power of Virtual DOM components, without the overhead: Familiar React API & patterns:

Preact 33.5k Dec 31, 2022
HTML Framework that allows you not to write JavaScript code.

EHTML (or Extended HTML) can be described as a set of custom elements that you can put on HTML page for different purposes and use cases. The main ide

Guseyn Ismayylov 171 Dec 29, 2022
Ember.js - A JavaScript framework for creating ambitious web applications

Ember.js is a JavaScript framework that greatly reduces the time, effort and resources needed to build any web application. It is focused on making yo

Ember.js 22.4k Jan 8, 2023
Meteor, the JavaScript App Platform

Meteor is an ultra-simple environment for building modern web applications. With Meteor you write apps: in modern JavaScript that send data over the w

Meteor 43.2k Jan 4, 2023
๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

Supporting Vue.js Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome ba

vuejs 201.7k Jan 8, 2023
Knockout makes it easier to create rich, responsive UIs with JavaScript

Knockout Knockout is a JavaScript MVVM (a modern variant of MVC) library that makes it easier to create rich, desktop-like user interfaces with JavaSc

Knockout.js 10.3k Jan 4, 2023
Lightweight MVC library for building JavaScript applications

Spine Spine is a lightweight MVC library for building JavaScript web applications. Spine gives you structure and then gets out of your way, allowing y

Spine JS Project 3.6k Jan 4, 2023
NativeScript empowers you to access native api's from JavaScript directly. Angular, Vue, Svelte, React and you name it compatible.

NativeScript empowers you to access native APIs from JavaScript directly. The framework currently provides iOS and Android runtimes for rich mobile de

NativeScript 22k Jan 4, 2023
A JavaScript Framework for Building Brilliant Applications

mithril.js What is Mithril? Installation Documentation Getting Help Contributing What is Mithril? A modern client-side JavaScript framework for buildi

null 13.5k Dec 26, 2022
A framework for real-time applications and REST APIs with JavaScript and TypeScript

A framework for real-time applications and REST APIs with JavaScript and TypeScript Feathers is a lightweight web-framework for creating real-time app

Feathers 14.2k Dec 28, 2022
A rugged, minimal framework for composing JavaScript behavior in your markup.

Alpine.js Alpine.js offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost. You get to keep your DOM,

Alpine.js 22.5k Dec 30, 2022
The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.

Bootstrap Sleek, intuitive, and powerful front-end framework for faster and easier web development. Explore Bootstrap docs ยป Report bug ยท Request feat

Bootstrap 161.1k Jan 4, 2023
JavaScript UI library for data-driven web applications

Road to 2.0 The master branch has new, in-progress version of w2ui. You might want to consider 1.5 branch that is stable and supports older browsers.

Vitali Malinouski 2.4k Jan 3, 2023
A JavaScript implementation of SOM, a minimal Smalltalk for teaching and research.

ohm-som A JavaScript implementation of SOM, a minimal Smalltalk for teaching and research. Just a hobby, won't be big and professional like TruffleSOM

Patrick Dubroy 16 Jun 25, 2021
A no-dependency, intuitive web framework from scratch in Javascript

Poseidon ?? Intro Poseidon is, to use a nice description by Reef, an anti-framework. It's a a no-dependency, component-based Javascript framework for

Amir Bolous 45 Nov 14, 2022