Monster is a lightweight, robust and easy-to-use library with modest ambitions. Monster integrates easily with your existing websites without taking over everything.
Here’s what Monster is all about. In section Getting Started
you can read how to integrate Monster into your own web projects.
Monster has a free license, and therefore you are free to customize Monster to your needs.
Monster is a collection of functions and classes that can help in the daily work with Javascript to get faster to the goal. Monster does not require you to be the only library, nor does it require you to use only Monster.
Monster itself has no dependencies and works perfectly with other frameworks like jQuery or Bootstrap.
The design goals of Monster’s core library are:
Easy integration with existing user interfaces.
Robust interfaces
Tested code and good code coverage.
No dependencies on other libraries
Why Components?
JavaScript web components are useful for creating reusable, modular and maintainable web applications. Below are some of the reasons why developers should choose to use a JavaScript web component framework such as MonsterJS:
Reusability: web components are self-contained entities that can be easily reused in different parts of an application, reducing the amount of duplicate code and increasing maintainability.
Modularity: Web components can be assembled from other web components, allowing developers to create complex user interfaces from small, modular building blocks.
Interoperability: Web components are developed based on web standards and are therefore compatible with other web technologies and frameworks. This allows developers to easily integrate web components into their existing applications.
Performance: Web components are lightweight and powerful, they can be rendered and updated quickly, which can improve the overall performance of web applications.
Acceptability: web components are increasingly used by browsers and developers and are part of the web platform, making it easy to find support and guidance online.
Flexible: web components are not tied to a specific framework, so developers can choose the tools that best suit their needs.
Overall, MonsterJS and its web components offer a great way to improve the scalability, maintainability and performance of web applications.
Getting Started
To use Monster, you must have a foundation in HTML, CSS, and JavaScript. If you are just
starting out in frontend development, it is recommended that you have a beginner’s guide
open while working through this guide.
You can also ask for help on Stack Overflow
by tagging your questions with “javascript” and “monster”.
Using Monster in the browser
To get started with Monster, all you need is a text editor and a browser. The best way to begin is to
copy the following example into a file and save it as index.html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Unleash your inner monster!</title>
</head>
<body>
<div>Your version is:
<span id="version"></span>
</div>
<script type="module">
import { Version } from 'https://cdn.skypack.dev/@schukai/[email protected]/source/types/version.js';
document.getElementById('version').innerText = new Version('1.0.0').toString();
</script>
</body>
</html>
Then, open this file in your browser. You have now used the ‘Version’ class from Monster to create a Version object,
which is output in a span.
Congratulations!
As shown in the version example, each Monster class or function can be used independently.
Alternatively, Monster can be used as a collection of many useful classes and functions via
the Monster namespace as a single JavaScript file.
In addition to being available on CDN providers like jsDelivr and Skypack, Monster can also
be obtained via NPM or the git repos.
Monster itself has no dependencies and does not impose any specific requirements,
so you can use it with Bootstrap, jQuery, or other frameworks.
Using Monster with NPM
To install Monster using npm, you will need to have Node.js and npm (which comes with Node.js) installed on your system.
Open a terminal or command prompt on your computer.
Run the following command: npm install @schukai/monster
This will install the latest version of Monster from the npm registry. If you want to install a
specific version of Monster, you can specify the version number after the package name,
like this: npm install @schukai/[email protected].
Once the installation is complete, you can import the modules in your JavaScript file like this:
import {Version} from '@schukai/monster/source/types/version.js';
console.log(new Version('1.0.0').toString());
Instead of npm you can of course also use yarn or pnpm.
Data
Functions and classes in this section are used to handle data.
Pathfinder
The Pathfinder class is used to access a specific path in a data object.
The Pathfinder class is used to access a specific path in a data object. The path is defined as a string.
The path is separated by a dot. The path can also be an array of strings. The path can also be a combination of both.
The Transformer class is used to transform data. The transformation is defined as a string.
import {Transformer} from '@schukai/monster/source/data/transformer.mjs';
const transformer = new Transformer("tolower")
console.log(transformer.run("HELLO"))
// ↦ hello
The following transformations are available:
command
parameter
alias
description
to-base64
base64, btob
Converts the value to base64
from-base64
atob
Converts the value from base64
call
function:param1:param2:…
Calling a callback function. The function can be defined in three places: either globally, in the context addCallback or in the passed object
default
value:type
??
If the value is undefined the first argument is returned, otherwise the value. The third optional parameter specifies the desired type. If no type is specified, string is used. Valid types are bool, string, int, float, undefined and object. An object default value must be specified as a base64 encoded json string. (since 1.12.0)
debug
the passed value is output (console) and returned
empty
Return empty String ""
first-key
default
Can be applied to objects and returns the value of the first key. All keys of the object are fetched and sorted. (since 1.23.0)
fromjson
Type conversion from a JSON string (since 1.12.0)
if
statement1:statement2
?
Is the ternary operator, the first parameter is the valid statement, the second is the false part. To use the current value in the queue, you can set the value keyword. On the other hand, if you want to have the static string “value”, you have to put one backslash \ in front of it and write value. the follow values are true: ‘on’, true, ’true’. If you want to have a space, you also have to write \ in front of the space.
index
key:default
property, key
Fetches a value from an object, an array, a map or a set
last-key
default
Can be applied to objects and returns the value of the last key. All keys of the object are fetched and sorted. (since 1.23.0)
length
count
Length of the string or entries of an array or object
nop
Do nothing
nth-key
index:default
Can be applied to objects and returns the value of the nth key. All keys of the object are fetched and sorted. (since 1.23.0)
nth-last-key
index:default
Can be applied to objects and returns the value of the nth key from behind. All keys of the object are fetched and sorted. (since 1.23.0)
path
path
The access to an object is done via a Pathfinder object
path-exists
path
Check if the specified path is available in the value (since 1.24.0)
plaintext
plain
All HTML tags are removed (*)
element-by-id
plain
All HTML tags are removed (*)
prefix
text
Adds a prefix
rawurlencode
URL coding
static
none
The Arguments value is used and passed to the value. Special characters \ and : can be quotet by a preceding .
substring
start:length
Returns a substring
suffix
text
Adds a suffix
translation
key:default
i18n
Translations can be applied. The translations must be stored in the DOM. (*) To use the current value as key the first parameter must be set to undefined.
tointeger
Type conversion to an integer value
tojson
Type conversion to a JSON string (since 1.8.0)
tolower
strtolower, tolowercase
The input value is converted to lowercase letters
tostring
Type conversion to a string.
toupper
strtoupper, touppercase
The input value is converted to uppercase letters
trim
Remove spaces at the beginning and end
ucfirst
First character large
ucwords
Any word beginning large
undefined
Return undefined
uniqid
Creates a string with a unique value (**)
(*) for this functionality the extension jsdom must be loaded in the nodejs context.
(**) for this command the crypt library is necessary in the nodejs context.
import * as Crypto from "@peculiar/webcrypto";
global['crypto'] = new Crypto.Crypto();
With the method setCallback(name, callback, context) you can define your own transformation functions.
The context parameter is optional and can be used to define the context in which the callback function is called.
If no context is specified, the global context is used. In the pipe the name of the callback function is used by prefixing it with a call:.
import { Transformer } from '@schukai/monster/source/data/transformer.mjs';
const transformer = new Transformer("call:myCallback");
transformer.setCallback("myCallback", function (value) {
return value + " world";
});
console.log(transformer.run("hello")); // hello world
Pipe
A Pipe is a class that is used to process data. The data is processed in a chain of functions.
The functions are called in the order in which they were added to the pipe. The data is passed from
one function to the next.
import {Pipe} from '@schukai/monster/source/data/pipe.mjs';
import {Pipe} from '@schukai/monster/source/data/pipe.mjs';
let obj = {
a: {
b: {
c: {
d: "world"
}
}
}
}
console.log(new Pipe('path:a.b.c.d | toupper | prefix:Hello\\ ').run(obj));
// ↦ Hello WORLD
The Pipe class use the Pathfinder class to
access the data and the Transformer class to transform the data.
Internationalisierung
The localization classes and functions support you in dealing with translations and country-specific settings.
Locale
The Locale class is used to determine the language and country settings.
The method parseLocale() parses a locale string and returns a Locale object.
import {parseLocale} from '@schukai/monster/source/i18n/locale.mjs';
var locale = parseLocale("en-US");
console.log(locale.language); // "en"
console.log(locale.country); // "US"
The Method getLocaleOfDocument() returns the Locale object of the current document.
import {getLocaleOfDocument} from '@schukai/monster/source/dom/locale.mjs';
var locale = getLocaleOfDocument();
console.log(locale.language); // "en"
console.log(locale.country); // "US"
In an HTML document you can set the language and country with the lang attribute.
<html lang="en-US">
The method getLocaleOfDocument() checks for the lang attribute first and takes
the browser locale as fallback. If no locale is available, English is taken.
Formatter & Translations
We need the Formatter and Translations class and the parseLocale() function to handle translations. In the context of the DOM we can also use the getLocaleOfDocument() method.
import {Translations} from '@schukai/monster/source/i18n/translations.js';
import {Formatter} from '@schukai/monster/source/text/formatter.js';
import {parseLocale} from '@schukai/monster/source/i18n/locale.js';
import {getLocaleOfDocument} from '@schukai/monster/source/dom/locale.js';
Let’s start with the function parseLocale(). This function can create a Locale object from a string.
So we can create the corresponding Locale object from the string en_GB.
If we move in the browser, so we can also use the function getLocaleOfDocument(). This function returns a locale object as a result.
This function looks if the HTML tag <html lang="en"> has a lang attribute. If no locale is defined, the default value is assumed to be en.
We now need an object with the translations. For this, we use the Translations class.
We can either define the translations ourselves or load them via an API.
// define translations
const translation = new Translations(parseLocale('en-GB'));
translation.assignTranslations({
text1: 'hello world!',
text2: {
'one': 'click once',
'other': 'click ${n | tostring} times' // this is where the pipe comes in
}
});
// fetch from API
const translation = new Fetch('https://example.com/${language}.json').getTranslation('en-GB');
// ↦ https://example.com/en.json
If we now have a translation, we can now read the desired strings. For this we use the method Translation.getText() or the method Translation.getPluralRuleText() for texts with more than one number.
const message = translation.getText('text1');
// -> hello world
To translate texts with number references, enter the desired number.
let n=1;
const message1 = translation.getPluralRuleText('text2', n);
// -> click once
n=2
const message2 = translation.getPluralRuleText('text2', n);
// -> click ${n} times
To replace the placeholder now, the formatter is used.
const text = new Formatter({n}).format(message2);
console.log(text)
// ↦ click 2 times
Finally, let’s take a look at the formatter class from the i18n module.
import {Formatter} from
'https://cdn.skypack.dev/@schukai/[email protected]/source/i18n/formatter.js';
A tranlate object can be passed directly to this class.
There is also the possibility to pass values in the format string.
// define translation
const translations = new Translations('en')
.assignTranslations({
// text with placeholder
message: "${animal} has eaten the ${food}!"
});
// without marker and inline values
new Formatter({}, translations).format("message::animal=dog::food=cake")
// ↦ dog has eaten the cake!
Translation
The Translation class encapsulates strings for a specific locale.
It is used to translate strings into a specific language and country.
import {Translation} from '@schukai/monster/source/i18n/translation.mjs';
const translation = new Translation("en-US");
translation.set("hello", "Hello World!");
// plural rules
translation.setText("text6", {
"zero": "There are no files on Disk.",
"one": "There is one file on Disk.",
"other": "There are files on Disk.",
"default": "There are files on Disk."
});
If you want to assign a complete translation object, you can use the assignTranslations() method.
translation.assignTranslations({
"hello": "Hello World!",
"text6": {
"zero": "There are no files on Disk.",
"one": "There is one file on Disk.",
"other": "There are files on Disk.",
"default": "There are files on Disk."
}
});
The getText() method returns the translated string for a given key.
translation.getText("hello"); // "Hello World!"
There are also methods for plural rules. The getPluralRuleText() method returns the translated string for a given key and a given number.
translation.getPluralRuleText("text6", 0); // "There are no files on Disk."
translation.getPluralRuleText("text6", 1); // "There is one file on Disk."
translation.getPluralRuleText("text6", 2); // "There are files on Disk."
Document Translation
First, you have to create a new script element with the data-monster-role="translations"
and the type="application/json" attribute. The content of the element must be a JSON object.
Then you have to assign the translations to the document. This can be done with the assignTranslationsToDocument() method.
This static method returns a promise. Than you can use the getDocumentTranslations() method to get the translations.
Finally, you can use the getText() method to get the translated string.
The URL can contain the placeholder ${language}, ${script}, ${region}, ${variants}, ${extlang} and ${privateUse}.
The placeholders will be replaced with the language, country and locale of the current document.
Now you can use the EmbedProvider to get the translations.
import {Embed} from '@schukai/monster/source/i18n/providers/embed.mjs';
const provider = new Embed('mmylocale');
provider.getTranslations('en-US').then(translations => {
console.log(translations);
});
DOM
The Document Object Model (DOM) is a programming interface for HTML and XML documents.
It represents the structure of a document as a tree-like structure, where each node in the
tree represents an element, attribute, or text content in the document.
JavaScript provides a set of functions and classes for working with the DOM, including methods
for creating, modifying, and querying elements, as well as handling events.
JavaScript’s DOM functions and classes can be divided into several categories:
Document: this includes the Document object, which represents the entire HTML or XML document and provides methods for manipulating the structure and content of the document.
Element: This includes classes such as HTMLElement, which represent an HTML element and provide methods for manipulating the attributes, content, and style of the element.
Event: This includes classes such as Event and EventTarget, which provide methods for processing and responding to events such as clicks, mouse movements, and keystrokes.
Node: This includes classes such as Node, which represent a node in the DOM tree and provide methods for processing the node’s parent and child nodes.
Selector: These include functions such as document.getElementById(), document.querySelector(), and document.querySelectorAll(), which are used to select elements from the DOM by their ID, class, or tag name.
By using these functions and classes, developers can create dynamic and interactive web pages
and develop a variety of web applications.
In this section, we will delve deeper into the functions and classes provided by Monster and provide
examples of their usage for manipulating the DOM and handling events.
Monster’s updater uses a DOM-based approach. The configuration and the template system are valid and parsable HTML.
The configuration is done via some special attributes with a data-monster- prefix.
Code is always the most informative. So let’s take a look at a complete example right away.
// The first thing to do is to include the Updater class.
import {Updater} from 'https://cdn.skypack.dev/@schukai/[email protected]/source/dom/updater.js';
// Now we prepare the html document.
// This is done here via script, but can also be inserted into the document as pure html.
// To do this, simply insert the tag <h1 data-monster-replace="path:headline"></h1>.
const body = document.querySelector('body');
const headline = document.createElement('h1');
headline.setAttribute('data-monster-replace','path:headline')
body.appendChild(headline);
// the data structure
let obj = {
headline: "Go!",
};
// Now comes the real magic. we pass the updater the parent HTMLElement
// and the desired data structure.
const updater = new Updater(body, obj);
// now we get the used data structure. why can't we take the original structure?
// the updater puts a proxy over the data structure and thus allows to monitor changes.
// We would not see changes to the original object.
const subject = updater.getSubject();
// now start the updater
updater.run();
// Now you can change the data structure and the HTML will follow these changes.
// to illustrate, let's put the change into a timer call.
setTimeout(function(){
console.log(obj);
subject['headline'] = "Hello!"
},1000);
We have seen how we can change the content of an htm element. now let’s look at what options are available.
Replace
The simplest manipulation is to replace the content of a HTMLElement. To do this, simply use the data-monster-replace attribute (see example).
The syntax is quite simple. The result of the attribute pipe is inserted as content of the HTMLElement. For the processing the Pipe
and Transformer class is used.
If, for example, you have an object x with the structure listed below and want to insert the value of the key b, you write: path:a.b.
The pipe can then be used to apply operators. For example, tolower can be used to convert everything to lowercase.
import {Updater} from 'https://cdn.skypack.dev/@schukai/[email protected]/source/dom/updater.js';
const body = document.querySelector('body');
const headline = document.createElement('h1');
headline.setAttribute('data-monster-replace','static:hello')
body.appendChild(headline);
// result in ↦ <div data-monster-replace="static:hello"></div>
new Updater(body).run();
Attributes
Attributes can be added via the data-monster-attributes attribute. The syntax is attribute name followed by a space and the desired pipe definition.
<div data-monster-attributes="id static:myid, class static:myclass">hello</div>
Remove
The data-monster-remove attribute can be used to remove html elements. it is important to note that this cannot be undone. Once removed, nodes will not be reinserted.
This tag is removed via the updater
<div data-monster-remove></div>
Insert
The strongest feature is adding elements to a node.
For this feature you need a template and the data-monster-insert attribute.
The syntax of the attribute is first an id followed by a space. This is then followed by the pipe command.
<ol data-monster-insert="myid path:a"></ol>
Furthermore, you need a template. The template must have the same string as id.
In this template, we define the structure of the new elements. In this case, the id is taken from the dataset index:id, converted to a string tostring, and an x is placed in front of it prefix:x.
The values for the corresponding data must be available as an array.
Below we have a complete example. Instead of specifying the template <template /> in HTML, it is constructed via javascript document.createElement('template'). But it is essentially the same.
You can easily add and delete values to the array. The DOM will be adjusted accordingly. The attribute data-monster-insert-reference identifies if the entry already exists.
Form Handling
Forms can be bound to a structure just like other structures via the updater class.
A new updater is created in this case via the following call.
const updater = new Updater(document.getElementById('form1'));
With the method Updater.getSubject() you can get the structure of the updater. If you want to use an already defined structure, you can pass it to the updater as a second parameter.
let subject = updater.getSubject();
console.log(subject);
Now we want a click on the checkbox to be mapped in the data structure.
To do this we need to extend the html with the data-monster-bind attribute.
The values or states of controls are mapped to the data structure via this binding.
In this case the status of the checkbox is mapped to the key state. If the checkbox is selected the field state contains the value on , otherwise state is undefined.
If you want to use another value instead of on, you can set the attribute value.
To see the magic the handling must still be switched on.
updater.enableEventProcessing()
Web Component
Web Components are a set of technologies that allow developers to create custom, reusable elements for use
in web pages and web applications. These elements, known as Custom Elements, can be created using JavaScript,
HTML, and CSS and are fully-featured and can be used just like any other standard HTML element.
Web Components are a key aspect of web development, as they enable developers to create reusable, modular
code that can be easily shared and integrated with other projects. Additionally, because Web Components
are part of the web platform and not tied to a specific framework or library, they are highly portable
and can be used in a wide variety of environments. Overall, Web Components provide a powerful and flexible
way to build web applications and create custom, reusable elements for web pages.
Create your own web component
This section is about how to create your own Web Component.
First, we create a class derived from CustomControl. The parent class CustomControl already implements some functions that will make life in the following easier.
class Button extends CustomControl {
}
The next step determines which tag the control should get in the HTML.
To be able to configure the control later, we have to create the possibility, to be able to create options. We can use the structures of the class CustomControl and only need to create a separate property default.
class Button extends CustomControl {
// ..... other implementations
get defaults() {
return Object.assign({}, super.defaults, {})
}
}
The templates of the control are also defined via this structure. In this way one can
the control with a standard and give the user of the control the possibility to adapt the templates.
Customize the templates.
So, now let’s get to work on the appearance of the control and create a template for it.
We want the button to use a simple HTML5 button.
<button>Hello!</button>
The main template of the button is maintained via the templates.main option.
So, we have to insert the HTML into the default structure introduced above. We can specify the HTML directly here.
If we now insert the HTML tag <monster-button></monster-button> into an HTML file
we get so far so unspectacular a button.
Now comes the magic. In the DOM there are two important methods that are called when a control is included and removed.
When a control is removed.
If a control is hooked into the DOM, the method connectedCallback is called.
When a control is removed from the DOM, on the other hand, the method
disconnectedCallback is called
We implement both methods in our new class.
class Button extends CustomControl {
// ..... other implementations
connectedCallback() {
super.connectedCallback();
}
disconnectedCallback() {
super.disconnectedCallback();
}
}
Within these two methods, we can now initialize structures or add and remove event handlers.
Adding and removing event handlers.
The CustomControl has two other important methods that can be overridden to initialize, they
can be overridden to initialize the control. These two methods
have no direct method name, but are hidden behind a symbol key.
symbol key.
import {
assembleMethodSymbol,
initMethodSymbol,
} from "@schukai/monster/dist/modules/dom/customelement.js";
class Button extends CustomControl {
// ..... other implementations
[initMethodSymbol]() {
super[initMethodSymbol]();
}
[assembleMethodSymbol]() {
super[assembleMethodSymbol]();
}
}
The method initMethodSymbol is called directly from the constructor and is used for one-time initialization of internal structures.
internal structures.
The method assembleMethodSymbol is called the first time the control is included in the DOM. If the control is removed and re-included, the assembleMethodSymbol method is called.
assembleMethodSymbol` is not called again.
Form component
Web forms are a way for users to enter and submit data on a web page.
They are created using HTML and can include a variety of input elements
such as text fields, checkboxes, radio buttons, and more.
Web forms are a crucial aspect of many websites, as they allow users to
interact with the site and provide information such as login credentials,
contact information, and more.
Create form
Usage
The Form component allows the user to create a form and in interaction with a datasource to change data.
// create element
const form = document.createElement('monster-form');
Input controls
A form needs input fields. These can be easily defined within the tag. Either via Javascript directly or via the markup.
The formula field ➊ are included as slotted elements in the shadow root ➋.
Datasource
One of the more interesting features of the form is the ability to connect the form to a data source.
A datasource has a simple API to read and write an object (see Monster Framework under Datasources).
In this example we use a RestAPI datasource, but other datasources work as well. The example url httpbin.org
is a service that provides a simple api with data. This is for this example only. You can of course specify your own
api here.
Now we have to report the data back to the datasource. For this we use the attribute data-monster-bind.
In this example we write the value in the same field, but we can also choose another field if for example the POST
api has a different structure.
What is a form without action? To be able to send the changed data we can add a button.
const button = document.createElement('monster-state-button');
// let's give the button a text
button.setOption('labels.button','click!')
// this attribute ensures that the form sets an action handler in the button.
button.setAttribute('data-monster-datasource-handler','write')
button.setOption('actions.click', undefined);
form.appendChild(button);
If we now click on the button, the modified dataset will be sent to the url previously specified in the RestAPI datasource.
Layout
The select control can be customized to your own needs. For this purpose, the control can be designed via
css.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The individual parts are shown in the following picture.
Custom button
Usage
The button control encapsulates a button and serves as a basis for derived controls.
// create element
const button = document.createElement('monster-button');
// insert element into the DOM
document.getElementById('body').appendChild(button);
<monster-button></monster-button>
Slotted Button
The text of the button can be defined either by the option labels.button.
// create element
const button = document.createElement('monster-button');
// insert element into the DOM
document.getElementById('body').appendChild(button);
// Label
button.setOption('labels.button','My Button');
Standard HTML buttons can listen to different events. Since the standard button sits in a shadowRoot the click event
is accessible via an option. The component button uses a callback to listen for click events.
To do this, you must pass a callback to the actions.click option.
The status button is a special form of the button and has an icon to display the status.
You can also define your own statuses. these must be specified in the options.
// create element
const button = document.createElement('monster-state-button');
// insert element into the DOM
document.getElementById('body').appendChild(button);
// Label
button.setOption('labels.button','My Button');
// set state: successful, activity or failed
button.setState('successful');
The button control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The color scheme of the button can be set using CSS class via the options.
You should always use a light color scheme for the status button, so that the icon is
the icon is clearly visible. When using the standard design, you should always use the
Outline variant should always be used.
The individual parts and slots are shown in the following picture.
Confirm button
Usage
The ConfirmButton component enables the display of a confirmation prompt before the final execution of an action.
// create element
const button = document.createElement('monster-confirm-button');
// set label
button.setOption('labels.button', 'click me!');
// insert element into the DOM
document.getElementById('body').appendChild(button);
Add confirm action
The confirm button can be given a function via the actions.confirm option.
button.setOption('actions.confirm', function (event) {
console.log('confirm');
button.hideDialog();
});
Add confirm action with state
The state is realized via a process queue.
button.setOption('actions.confirm', function (event) {
const self = this;
new Processing(() => {
self.setState('activity'); // set state
button.setOption('disabled', true);
}, 2000, () => { // delay 2000 milliseconds
button.hideDialog();
}).run().then(() => {
button.setOption('disabled', undefined); // remove state
});
});
Layout
The confirm-button control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The nested parts can each be addressed via the part name and the subpart name. So the part button is addressable from the confirm button via confirm-button.
The individual parts and slots are shown in the following picture.
Searchable select
Usage
Select component allows user to pick any amount of option from the given data:
// create element
const select = document.createElement('monster-select');
// set multiselect
select.setOption('type', 'checkbox');
// set options
select.setOption('options', [
{value: 'en', label: 'United Kingdom <img width=20
src="https://raw.githubusercontent.com/lipis/flag-icon-css/master/flags/4x3/gb.svg">'},
{value: 'se', label: 'Sverige <img width=20
src="https://raw.githubusercontent.com/lipis/flag-icon-css/master/flags/4x3/se.svg">'},
{value: 'de', label: 'Deutschland <img width=20
src="https://raw.githubusercontent.com/lipis/flag-icon-css/master/flags/4x3/de.svg">'}
]);
// insert element into the DOM
document.getElementById('body').appendChild(select);
Single select
Radios are used for the single selection.
select.setOption('type', 'radio');
Multiselect
Checkboxes are used for multiple selection.
select.setOption('type', 'checkbox');
Import data
The options can be imported from an object. The object can be read in either directly via
Select.importOptions() or indirectly via a URL. In the example, a json file is
imported via https://monsterjs.org/assets/world.json`.
It is also possible to filter values. This is done via the filter parameter. Further details on the structure of the
map can be found in the Monster documentation.
The component can be translated into different languages. For this you simply have to translate
the corresponding labels. This can be done using the Select.setOption() method.
select.setOption('labels', {
'cannot-be-loaded': 'The data cannot be loaded',
'no-options-available': 'No options available'
});
You can also use the translation function. Therefore, the component can be translated via the
Select.updateI18n() methods.
To see the keys of the translations, you can look at the default values under the labels key.
selects.getOption('labels')
// ↦ { .... }
Layout
The select control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The individual parts are shown in the following picture.
Searchable tree select
Usage
The TreeSelect control is derived from Select and therefore inherits all properties and functions.
It extends the control by the display of hierarchical data.
const treeselect = document.createElement('monster-tree-select');
// URL
treeselect.setOption('url', 'https://monsterjs.org/assets/14-forms-treeselect-data.json');
// Multiselect
treeselect.setOption('type', 'checkbox');
// search for data in dataset
treeselect.setOption('mapping.selector', 'dataset.*');
// define label and key
treeselect.setOption('mapping.labelTemplate', '${localeLabel | index:en}');
treeselect.setOption('mapping.valueTemplate', '${cid | tostring }');
// wich field is the parent ID?
treeselect.setOption('mapping.parentTemplate', 'parentCID');
treeselect.setOption('mapping.idTemplate', 'cid');
// append
document.getElementById('container').appendChild(treeselect);
The tree select control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
#tab::part(popper) {
background-color: white;
}
The individual parts are shown in the following picture.
Tabs
Usage
The Tabs component allows the user to switch between multiple contents based on a navigation bar.
The text for the buttons is formed from the content of the divs. No tab is active.
<monster-tabs>
<div>this is tab 1</div>
<div>this is tab 2</div>
</monster-tabs>
Active Tab
To set a tab active, you need to give the desired div the css class active`.
// tabs
const tabs = document.createElement('monster-tabs');
// tab1
const tab1 = document.createElement('div');
tab1.innerHTML = 'this is tab 1';
// this tab should be active
tab1.classList.add('active')
tabs.appendChild(tab1)
// tab2
const tab2 = document.createElement('div');
tab2.innerHTML = 'this is tab 2';
tabs.appendChild(tab2)
// append to document
document.getElementById('example').appendChild(tabs);
<monster-tabs>
<div class="active">this is tab 1</div>
<div>this is tab 2</div>
</monster-tabs>
Tabs with label and icon
To use an explicit text for the button, you can use the data-monster-button-label attribute.
If you also want to specify an icon, the attribute data-monster-button-iocon` is available.
<monster-tabs>
<div class="active" data-monster-button-label="FIRST">this is tab 1</div>
<div data-monster-button-label="SECOND"
data-monster-button-icon="https://monsterjs.org/monster.png">this is tab 2</div>
</monster-tabs>
Prefix and suffix
If you want to add content before or after the navigation buttons, you can do so using the start and
end slots.
// tabs
const tabs = document.createElement('monster-tabs');
// prefix
const prefix = document.createElement('div');
prefix.innerHTML='this is a <b>prefix</b>';
prefix.setAttribute('slot','start')
tabs.appendChild(prefix);
// suffix
const suffix = document.createElement('div');
suffix.innerHTML='this is a <b>suffix</b>';
suffix.setAttribute('slot','end')
tabs.appendChild(suffix);
// tab1
const tab1 = document.createElement('div');
tab1.innerHTML = 'this is tab 1';
tab1.classList.add('active')
tab1.setAttribute('data-monster-button-label','FIRST');
tabs.appendChild(tab1)
// tab2
const tab2 = document.createElement('div');
tab2.innerHTML = 'this is tab 2';
tab2.setAttribute('data-monster-button-label','SECOND');
tabs.appendChild(tab2)
// append to document
document.getElementById('example').appendChild(tabs);
<monster-tabs>
<div class="active" data-monster-button-label="FIRST">this is tab 1</div>
<div data-monster-button-label="SECOND">this is tab 2</div>
<div slot="start">this is a <b>prefix</b></div>
<div slot="end">this is a <b>suffix</b></div>
</monster-tabs>
Remove tabs
Tabs can be removed from the DOM. To do this, the desired content must have the attribute data-monster-removable.
If you add multiple tabs and there is no space for newer tabs, they will be moved to a popup. You can see this by the ⋮ sign.
<monster-tabs>
<div class="active"
data-monster-button-label="FIRST"
data-monster-removable="true">this is tab 1</div>
<div data-monster-button-label="SECOND"
data-monster-removable="true">this is tab 2</div>
</monster-tabs>
Fetch tab content
The content of a tab can also be fetched by specifying the attribute data-monster-url with the url of
the desired content. The tab is loaded only once. If you want to load the tab fresh from the server for each show,
you can specify the attribute data-monster-reload.
The tabs control can be customized to your own needs. For this purpose, the control can be designed via
css.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The individual parts and slots are shown in the following picture.
Reload
Usage
The Reload component allows the user to reload a content via URL. The content is reloaded only when the
element is in the viewport. The IntersectionObserver API is used.
Im Standard wird der Inhalt nur einmal geladen. Möchte man den Inhalt immer wieder neu Laden,
so muss die Option data-monster-reload auf “always” gesetzt werden.
The individual parts and slots are shown in the following picture.
Message State button
Usage
The MessageStateButton button can be used to display a button with a message.
The message is displayed when the method showMessage() is called.
The message is hidden when the method hideMessage() is called.
// create element
const button = document.createElement('monster-message-state-button');
// set label
button.setOption('labels.button', 'click me!');
Set Message
The message can be set via the method setMessage(). The message can be a string or an HTML element.
// create element
const button = document.createElement('monster-message-state-button');
// set label
button.setOption('labels.button', 'click me!');
// set message
button.setMessage('This is a message');
// show message
button.showMessage();
Layout
The message-state-button control can be customized to your own needs. For this purpose, the control can be designed via
CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The nested parts can each be addressed via the part name and the subpart name. So the part button is
addressable from the confirm button via message-state-button.
The individual parts and slots are shown in the following picture.
State component
The state component is a simple state display component.
It is used to display the current state of the application.
Usage
The status component is a simple graphical display that specifies a structure of elements.
The aim of this component is to enable a uniform representation of such displays.
The component is composed of a visual, a heading and a text. Actions (buttons) can also be displayed.
The state control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The individual parts and slots are shown in the following picture.
Notify Component
The notify component is a simple notification component.
Message
The notify message component is a simple notification message.
Usage
The notify component is a simple graphical display that specifies a notification.
Layout
The message control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The individual parts and slots are shown in the following picture.
Notify
The notify component encapsulates the notify message component.
Usage
The notify component is a simple graphical display that specifies a notification.
Layout
The notify control can be customized to your own needs. For this purpose, the control can be designed via CSS.
The different parts of the control can be designed using CSS. Since the internals of the component are
in a shadow tree, access
is via css pseudo-element parts.
The individual parts and slots are shown in the following picture.
Style
The CSS Style guide for Monster is a set of guidelines and best practices for writing and organizing CSS code.
It is designed to help developers maintain a consistent and organized codebase, making it easier to read,
understand, and modify. The style guide covers a wide range of topics, including naming conventions,
code organization, and performance optimization. Following the guidelines in this style guide will
help ensure that your CSS code is clean, maintainable, and efficient.
The following example shows how to include the stylesheets independently of the rest of the document.
<!-- here we define the desired content -->
<template id="contenttemplate">
<p>this is an example</p>
</template>
<script type="module">
// here we import the stylesheets
import {NormalizeStyleSheet} from 'https://cdn.skypack.dev/@schukai/[email protected]/source/stylesheet/normalize.mjs';
import {PropertyStyleSheet} from 'https://cdn.skypack.dev/@schukai/[email protected]/source/stylesheet/property.mjs';
import {ColorStyleSheet} from 'https://cdn.skypack.dev/@schukai/[email protected]/source/stylesheet/color.mjs';
import {ThemeStyleSheet} from 'https://cdn.skypack.dev/@schukai/[email protected]/source/stylesheet/theme.mjs';
// we create a node
const node = document.createElement('div');
// we attach the shadow root to the node
const shadow = node.attachShadow({ mode: 'open' });
// we clone the template and attach it to the shadow root
const template = document.getElementById('contenttemplate');
shadow.appendChild(template.content.cloneNode(true));
// we attach the stylesheets to the shadow root
shadow.adoptedStyleSheets = [NormalizeStyleSheet, PropertyStyleSheet,ColorStyleSheet, ThemeStyleSheet];
// we attach the node to the body
document.body.appendChild(node);
</script>
Color
Theme colors
<div class="monster-theme-primary-1"></div>>
The theme colors are listed below. The values must be prefixed with monster-theme-. The colors contain a definition for the background and the text. The color scheme is optimized for display in light and dark mode.
primary-1
primary-2
primary-3
primary-4
secondary-1
secondary-2
secondary-3
secondary-4
tertiary-1
tertiary-2
tertiary-3
tertiary-4
destructive-1
destructive-2
destructive-3
destructive-4
success-1
success-2
success-3
success-4
warning-1
warning-2
warning-3
warning-4
error-1
error-2
error-3
error-4
selection-1
selection-2
selection-3
selection-4
Special colors
<div class="monster-color-neutral-1"></div>>
The special colors are listed below. The values must be prefixed with monster-color-. The colors contain a definition for the background or the text.
neutral-1
neutral-2
neutral-3 + bg-color-primary-3
neutral-4 + bg-color-primary-4
neutral-1 + bg-color-secondary-1
neutral-1 + bg-color-secondary-2
neutral-1 + bg-color-secondary-3
neutral-4 + bg-color-secondary-4
neutral-1 + bg-color-secondary-1 + border-primary
neutral-1 + bg-color-secondary-2 + border-color-2
neutral-1 + bg-color-secondary-3 + border-color-3
neutral-4 + bg-color-secondary-4 + border-color-4
Border colors
<div class="monster-border-primary-1"></div>>
The border colors are listed below. The values must be prefixed with monster-. The colors contain a definition for the border including the border width and the border style.
This page is a demonstration of the elements that can be formatted
using Monster. It is not intended to be a comprehensive guide to
typography, but rather a reference of the styles that are available.
Basic Typography
All the typography of Monster uses
rem for sizing. This means that accessibility is
maintained for those who change their browser font size. The body element
has a size of 1.15rem which makes all the standard
font sizes slightly larger. This equates to 18.4px for
paragraph text, instead of the standard 16px.
The heading elements also have an increased top margin in order to break blocks of text up better.
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Links & Buttons
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
There are a number of other typography elements that you can use with Monster. Some of the common ones
are:
All the standard stuff, like bold, italic and underlined text.
Highlighting text.
Adding inline code using the code element.
Displaying keyboard commands like ALT+F4 using the kbd element.
Lists
We all love a perfect list?
Item 1
Item 2
Item 3
Do this thing
Do that thing
Do the other thing
Blockquotes
Sometimes you may want to quote someone else in your HTML. For this we use the blockquote element. Here’s what a quote looks like with
Monster:
Friends don’t spy; true friendship is about privacy, too.
– Stephen King
Code blocks
Code blocks are different from the inline code element.
Code blocks are used when you want to display a block of code, like this:
Other HTML elements
Article
This is an article
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum.
Section
Sections are good for splitting up a page into multiple…sections.
This is a section
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum.
Images
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur.This is a black swan
Accordions
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.Click to open
Yeah!🙂
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
Table
Name
Number
Jackie
012345
Lucy
112346
David
493029
Kerry
395499
Steve
002458
Form
Build
The styles are defined as PostCSS files. For this reason, you must parse these files with PostCSS to
generate CSS or Javascript files from them.
The following tool is recommended for this purpose: PostCSS.
The following plugins are used in the build script:
#!/usr/bin/env node
import fs from 'fs';
import postcss from 'postcss'; // https://postcss.org/
// https://github.com/postcss/postcss-import
import importCss from 'postcss-import';
// https://github.com/postcss/postcss-mixins
import mixins from 'postcss-mixins';
// https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting
import nesting from 'postcss-nesting';
// https://github.com/csstools/postcss-normalize
import normalize from 'postcss-normalize';
// https://github.com/notiv-nt/postcss-fluid
import fluid from 'postcss-fluid';
// https://github.com/antyakushev/postcss-for
import forStruct from 'postcss-for';
// https://github.com/madeleineostoja/postcss-responsive-type
import responsiveType from 'postcss-responsive-type';
// https://github.com/postcss/autoprefixer
import autoprefixer from 'autoprefixer';
// https://cssnano.co/
import cssnano from 'cssnano';
const sourceFile = 'source/main.pcss';
fs.readFile(sourceFile, (err, css) => {
postcss([
importCss(), // This plugin should probably
// be used as the first plugin
// of your list.
mixins,
nesting(),
normalize,
fluid,
forStruct,
responsiveType,
autoprefixer,
cssnano,
])
.process(css, {from: sourceFile})
.then(result => {
console.log(result.css)
}).catch(err => {
console.log(err)
})
})
The plugins do different things. For example, the postcss-normalize creates a CSS file that contains the CSS reset.
By using of the import plugin you can use the CSS instructions and mixin from monster.
In the monster library, we use current functions and objects for the implementation. Some functions may not run on older runtimes.
There are several ways to increase compatibility.
One way is Babel and the @babel/preset-env preset.
More information about the browsers supported by Babel can be found in
the browserslist project.
Polifyll
As a design decision, we decided against any kind of polyfill in our code.
This not only benefits the codebase, but also makes testing easier.
A more effective way to compensate for incompatibilities is to add missing functionality via external polyfills.
To avoid having to search for and include every polyfill yourself, you can use
services like polyfill.io. These can inject the missing functions and objects for each browser.
The URL builder can be used to compile the desired polyfills.
You can also automate the creation of the URL. For this you can install the tool create-polyfill-service-url.
With the following call the tool analyzes your script and throws out the desired URL.
npm i create-polyfill-service-url
With the following call the tool analyzes your script and throws out the desired URL.