Meefik's Blog

Freedom and Open Source

UX framework for JavaScript libraries

02 Dec 2021 | javascript

In one of my JS projects, I needed to implement UX interfaces in the Web SDK. Such a Web SDK was embedded on pages of third-party sites and for security reasons should not contain any external dependencies, including libraries like React. For these purposes, an own implementation of the UX framework was created, which can be embedded on the country of any site without problems and conflicts.

The code is implemented as a JS library and posted on GitHub under the MIT license. Build size - 12kb uncompressed (4kb gzipped).


The library consists of the following modules (classes):

Components and states

Usually the application consists of separate interconnected components. The Component class is used to describe the logic of each UX component. This includes the following functionality:

In addition, there is a set of component methods that allow you to manage the state, subscribe to events, etc.

An example of a component description:

import { Component } from 'libux';

export default class MyView extends Component {
  constructor (...args) {
    // this.params - includes this component arguments
  template () {
    return `<div>Hello <%- this.state.text %>!</div>`;
  data() {
    return {
      text: 'World'
  events() {
    return [
      mounted () {
        // ...


Localization of components allows you to display text information in different languages. This functionality is implemented in the Locale class.

Example of using localization:

import { Locale } from 'libux';

// create a new instance
const locales = { 
  en: { hello: 'Hello %{name}!' },
  ru: { hello: 'Привет %{name}!' }
const l10n = new Locale({ locales, lang: 'en' });
// get translation for specified path
l10n.t('hello', { name: 'World' }); // Hello World!
// list of supported languages
l10n.languages; // ['en', 'ru']
// switch to localization 'ru'
l10n.update({ lang: 'ru' });

Hash Routing

Routing at the application level allows you to organize the logic of switching components (pages of the SPA application). This functionality is implemented in the HashRouter class.

import { HashRouter } from 'libux';
import TodoView from 'views/todo';

const router = new HashRouter({
  routes: {
    '#/': TodoView


Services are the layer between the components and the backend API. They implement CRUD functions for exchanging data with the backend. This functionality is implemented in the Service class.

const service = new Service({
  url: 'http://localhost:3000/api/items'
// create new record{ id: '1', field1: 'a', field2: 'b' });
// get all records
// get the record by id
// update the record by id
service.put('1', { field1: 'c', field2: 'd' });
// remove the record by id

CSS modules

Styles are recommended to be connected as CSS modules. Each style will be assigned a unique identifier during assembly, which allows you to avoid conflicts with other styles on the page. In the project code, you will need to import a style file and call specific styles from the imported file by their name in it.

Example of using CSS modules:

import css from 'todomvc-app-css/index.css';

export default class TodoView extends Component {
  template () {
    return `
    <section class="${css.todoapp}">
    <footer class="${}">

The project has documentation in JSDoc format and a tutorial with an example of use in the form of the To-Do List application.