A frontend framework built entirely on web standards.
Modular Cube is a frontend framework that builds directly on web standards, enabling modular and maintainable applications without virtual DOMs or build pipelines.
Modular Cube is a frontend framework designed around web standards. It operates entirely on native browser features such as Custom Elements, HTML Templates, ES Modules, and the Shadow DOM. This foundation enables user interface components to be defined with standard HTML and JavaScript while supporting scoped rendering, declarative structure, and encapsulated behaviors. The framework avoids virtual DOM abstractions and transpilation layers. By following this model, Modular Cube supports the development of modular, maintainable applications that run directly in the browser without additional build processes or external dependencies.
Built entirely on native browser features such as Custom Elements, Shadow DOM, and ES Modules. No external dependencies or build tools are required.
Avoids the overhead from complex runtime engines or compilation steps, making applications faster to load and easier to maintain.
Encapsulation by design, with isolated structure and styling through Shadow DOM, ensuring clean separation without global conflicts.
Interoperable and compatible, since it uses only HTML, CSS, and JavaScript, allowing seamless integration with existing codebases and libraries.
Reduced abstraction layers, which promotes long-term sustainability, predictability, and easier debugging.
Embed JavaScript expressions directly in your HTML using ${this.expression}. Supported in text content, attributes, class names, and inline styles.
Use if directives and its extended forms (e.g. else if, else) to selectively include elements in the DOM based on runtime conditions.
Use forEach directives to generate repeated markup from iterable data structures.
Bind native DOM events using a consistent pattern (clickEvent, inputEvent, etc.) to trigger scoped logic without manually registering listeners.
DOM updates are scoped and localized, reducing overhead and eliminating re-renders.
The architecture of Modular Cube is structured around the core features natively supported by browsers. By relying on these capabilities, the framework ensures that components remain portable, efficient, and aligned with the evolution of the web platform.
Encapsulate behavior, state, and rendering logic in self-contained components defined as JavaScript classes. Each element is registered as a native HTML tag, allowing seamless integration into the DOM.
Provides reusable blocks of markup that are parsed but not rendered immediately. Templates serve as the foundation for dynamic rendering and runtime instantiation.
Enable modular development by defining clear boundaries for imports and exports. All components and logic are authored as ES modules, ensuring compatibility with the standard JavaScript module system.
Delivers encapsulation of both structure and styling, isolating internal implementations from the global DOM while supporting predictable component behavior.
Modular Cube does not aim to create a new way of building the web, it simply leverages the web as it exists today. Its goal is to empower developers to write UI code that is expressive, explicit, and maintainable, while avoiding the hidden complexity often introduced by large abstractions. It makes no assumptions about how your application is structured, but provides lightweight conventions to support common frontend needs: data-binding, conditional logic, event handling, and templating. By using only platform features, Modular Cube ensures forward compatibility and encourages a development style that aligns closely with how browsers operate. It is ideal for projects where performance, clarity, and long-term maintainability are key concerns.
These web standards work together to provide a consistent foundation for building components. They ensure that applications remain compatible with the native browser environment, while keeping the architecture simple and easy to extend.
Modular Cube lifecycle builds on the native Web Component lifecycle, extending it with custom states for more granular control over initialization and rendering. This ensures components are predictable, configurable, and modular throughout their lifetime in the DOM.
The lifecycle of a component defines the sequence of stages a component passes through from creation to removal. It combines standard Web Component callbacks with framework specific processing states to ensure proper initialization, configuration, and rendering.
constructor()
connectedCallback()
adoptedCallback()
attributeChangedCallback()
disconnectedCallback()
This diagram provides a simplified, linear view of the component lifecycle. A quick overview to understand the sequence of events and the internal states of a Modular Cube component.
When a component instance is created, the constructor method is invoked.
In Modular Cube, this immediately calls the preProcess state. At this stage, the component loads and validates its configuration, ensuring all required parameters (such as references to HTML, CSS, or behavior settings) are in place before any further lifecycle steps begin.
When a componentβs constructor is invoked, the preProcess state is automatically executed.
During this stage, configuration data is loaded, validated, and prepared before any rendering or attachment to the DOM occurs.
The constructor expects a mandatory configuration object with the following structure.
(MyComponent.config.json)
(MyComponent.js)
The connectedCallback() method is invoked automatically when a custom element is added to the DOM.
This marks the point where the component becomes active and begins its operational lifecycle.
This stage is aligned with the toProcess, atProcess, and inProcess states, which provide a structured sequence for initialization, rendering, and post-render logic.
This structured approach ensures that components are consistently initialized and rendered in a predictable order, reducing errors and improving maintainability.
When the component is first attached to the DOM, it enters the toProcess state.
This marks the beginning of the active lifecycle, where the component validates prerequisites and prepares resources, but no rendering has yet taken place.
Immediately after prerequisites are resolved within connectedCallback, the atProcess state runs.
The component has reached the point where rendering logic is about to be executed.
This state occurs after the component has completed its rendering phase. The DOM is now fully available for manipulation, and all initial behaviors are active. At this point, logic that depends on the rendered structure, such as querying the DOM with querySelector, setting focus, or attaching runtime event listeners can be safely executed.
The adoptedCallback is a lifecycle method that is called when a custom element is moved from one document to another, such as between iframes or windows.
The attributeChangedCallback is a lifecycle method in Web Components, specifically in the Custom Elements API.
It's used in custom HTML elements to detect when one of the element's observed attributes has changed.
The disconnectedCallback is a lifecycle method thatβs called when a custom element is removed from the DOM.
The Modular Cube component lifecycle defines how components transition through initialization, configuration, rendering, and cleanup.
It combines the standard Web Component lifecycle methods with custom internal states preProcess, toProcess, atProcess, and inProcess to ensure predictable behavior, structured processing, and safe DOM interactions throughout a componentβs existence.
The component lifecycle in Modular Cube unifies the standard Web Component callbacks with additional custom states. This approach establishes a predictable sequence in which configuration is validated, resources are prepared, rendering takes place, and post-render behavior becomes available. By following this structured progression, components remain consistent, modular, and easier to maintain, regardless of complexity or use case.
Configuration files, initialization logic, and the main entry point reside at the root level.
UI components are grouped within the app/ directory.
Supporting folders such as static/, modules/, and services/ are used to manage assets, reusable functionality, and core application logic.
This organization establishes distinct responsibilities for different parts of the project, making it easier to navigate, maintain, and extend over time.
To make a component available to the application, it must be registered in the global application configuration file: app.config.json.
This setup allows the framework to dynamically load and define the components at runtime.
The application configuration file app.config.json contains a root object named modularCube, which describes both the application entry point and the components that will be registered.
The application attribute is optional. Its purpose is to define the root application container.
Dom.init(), it first looks at the components attribute list.
If an entry component (for instance, app-root) is defined there, it will be instantiated as the root.
components attribute list, Dom.init() will then check whether an application attribute exists.
If present, the application will be used to define and initialize the root container.
The init.js file is the bootstrap script.
Its job is to initialize your application, load the configuration, and register components before rendering.
After defining and registering all components, the application must initialize the system using the Dom.init() method.
By default, app.config.json should be placed at the same folder level as init.js.
If no parameter is provided, the initializer will look for it automatically.
If the configuration file is stored elsewhere, you can provide its path explicitly:
The index.html is the root document of your project.
It loads the initialization script and acts as the starting point for rendering UI components.
To ensure components are initialized properly at application startup, the init.js file must be imported in the main HTML file.
The import map, initialization script, and root component provide the foundation of the application.
The index.html file serves as the starting point where these elements are brought together to initialize and render the user interface.
Each component in Modular Cube is encapsulated using the Shadow DOM to ensure scoped styles and isolated behavior. By convention, a component can be composed of four main files:
The framework allows you to keep HTML and CSS in separate files for clarity.
A configuration file (.config.json) to declare metadata, file paths, and runtime options.
A CSS stylesheet (.css) to provide encapsulated styles.
An HTML template (.html) to define the componentβs structure.
A JavaScript module (.js) to implement the componentβs logic and lifecycle.
Together, these files ensure that each component remains self-contained, easy to reason about, and reusable across different parts of the application.
The configuration file defines metadata, file references, and runtime behaviors for the component.
It specifies the paths to the associated HTML and CSS files, along with options such as appendToBody, lazyLoading, and debug.
The stylesheet provides styles scoped to the component through the Shadow DOM. This ensures that styles remain encapsulated and do not leak into the global document. Keeping styles in a separate file helps maintain a clean separation between structure, logic, and presentation.
The HTML template defines the componentβs structure and static markup. It serves as the foundation of the componentβs UI, which is later combined with the stylesheet and logic during initialization. Using an external template file improves readability and keeps layout concerns separate from logic.
The JavaScript file implements the componentβs logic, lifecycle, and behaviors.
It loads the configuration, processes the referenced HTML and CSS files (via preProcess()), and manages dynamic interactions.
This file is responsible for defining how the component behaves.
Each of these files plays a specific role in defining a component.
The configuration file describes its metadata and behavior, the CSS handles encapsulated styling, the HTML defines its structure, and the JavaScript manages its logic and lifecycle.
Together, they provide a clear and modular approach to building self-contained, maintainable components.
HTML directives provide a declarative way to extend component templates by using attributes. They make components easier to read and maintain by clearly expressing intent in the markup. Directives support dynamic binding, allowing variables, expressions, or configuration values to be injected directly into the template. They can also control behavior, such as managing conditional rendering, iterating over collections, or binding events to elements.
Variables in Modular Cube templates are expressed in two complementary forms: template interpolation and parameter injection. Both approaches allow component data to be incorporated into the DOM in a controlled and explicit manner, but they serve distinct purposes.
The template interpolation enables the embedding of JavaScript expressions directly within HTML content, using the ${this.expression} syntax.
This mechanism allows dynamic rendering of component state and computed values inline within native HTML templates.
Interpolation is resolved at render time and evaluated within the current data context (typically the component instance this or the shadow root scope).
Only valid JavaScript expressions are allowed. These must reference properties or methods available in the current scope.
Functions used within expressions must be side-effect-free and return a value.
Expressions should remain simple and easy to read. Complex logic or deeply nested expressions should be avoided.
Expressions are enclosed in $ { expression }:
class, title, placeholder, ... ).Inspector View (Elements)
The parameter injection feature provides a mechanism to inject parameter values directly into templates.
Unlike interpolation, which operates inline, parameter injection designates explicit placeholder elements that are fully replaced with evaluated values during the initial rendering.
The <param value=""> element is used as a placeholder for injecting parameter values into HTML templates.
At render time, the placeholder is replaced by the evaluated parameter, and the <param value=""> tag itself does not persist in the DOM.
Each <param> element with a value attribute is replaced with the current value of the corresponding parameter during the initial render.
Parameter values are evaluated from the componentβs declared parameter scope.
Complex or computed values should be resolved before assignment to parameters.
The <param> tag is a placeholder element and does not produce standalone DOM elements after rendering; it is replaced entirely by the parameterβs value.
Parameter injection is expressed using the <param value=""> element.
${this.expression}), parameter injection cannot be used inside attributes such as class, style, or title.<param> element is limited to injecting values directly into DOM content.Inspector View (Elements)
Together, interpolation and parameter injection provide complementary approaches for embedding dynamic values into component templates. While interpolation supports inline expressions within attributes and text nodes, parameter injection offers a direct mechanism for inserting parameter values into the DOM.
The if directive provides conditional rendering in HTML templates using declarative expressions. It enables developers to control whether a given element and its children should be rendered based on the evaluation of a boolean condition.
Single Condition Per Element: Each element can only have one conditional directive (if, elseIf, or else).
Evaluation Order: Conditions are evaluated top-to-bottom. The first matching branch is rendered; subsequent branches are skipped.
Mutual Exclusivity: Only one element in a chain (if β elseIf β else) is rendered at a time.
Expression Validity: Conditions must resolve to a boolean value or an expression that can be evaluated to true/false.
Clarity Over Complexity: Keep conditions simple and readable. Prefer computed properties or helper methods for complex logic.
Mutual Exclusivity: Only one element in a chain (if β elseIf β else) is rendered at a time.
Conditional directives are expressed as HTML attributes on elements and evaluated at render time:
if="${this.expression}" β Renders the element only if the expression evaluates to true.elseIf="${this.expression}" β Renders the element if all preceding if/elseIf conditions are false and this expression evaluates to true.else β Renders the element if all preceding if/elseIf conditions are false.Supported Contexts:
if β elseIf β else.this and may reference component properties or methods.Inspector View (Elements)
Inspector View (Elements)
Inspector View (Elements)
In JavaScript, you can absolutely use if, else if, else if without a final else.
The else block is completely optional.
ifif...elseif...else if...elseif...else if...else if (with or without else)
The if directive allows declarative, structured control of what elements are rendered based on logical conditions. Support for else if, else, and nested conditionals provides flexibility while maintaining clear and predictable rendering behavior.
The use of native HTML syntax and controlled evaluation reinforces clarity, performance, and consistency with modern web development practices.
The forEach directive in enables declarative iteration over collections within HTML templates. It renders a repeated structure for each item in a given array or iterable, following a clear and scoped expression pattern. This approach brings structured, readable list rendering to markup using standard JavaScript expression syntax. This directive is designed to integrate seamlessly with the component's data context and maintain clarity in both simple and nested list structures.
Scoped Variables: The loop variable is only valid inside the iteration block. It should not conflict with variables declared in outer scopes.
Combined with Directives: Loop-generated elements can also use conditional directives (if, elseIf, else) within the iteration body.
Static and Dynamic Data: Works with both static arrays defined at initialization and dynamic data updated during component lifecycle.
The forEach directive is expressed as an HTML attribute and enables iteration over iterable data structures:
${this.forExpression} β Repeats the element for each value in the iterable this.items, binding the current value to the loop variable.Supported Contexts:
${this.forExpressionItem}) or parameter injection (<param value="${this.forExpressionItem}">).Inspector View (Elements)
The forEach directive offers a concise and powerful way to generate HTML content dynamically based on collection data. With native expression support and clear scope handling, it supports structured iteration at any depth and promotes maintainable template design. Repeated content is easy to define and aligns with modern rendering practices through direct integration with JavaScript evaluation and native web capabilities.
HTML directives support binding JavaScript event handlers directly within your markup using a simple and consistent syntax.
It handle DOM events like click, input, keydown, mouseenter, and more.
These bindings follow standard JavaScript event behavior but are declared directly in the template, no need for addEventListener or inline onclick attributes.
Use the format: placeholderEvent="this.functionCall(...)".
The event name must be lowercase and match a standard DOM event (e.g. click, input, keydown).
You must append Event to the event name: clickEvent, inputEvent, keydownEvent, etc.
The value must be a valid JavaScript function call (with or without arguments).
The $event object can be passed to access native event data.
Inspector View (Console)
$event gives you access to native event details (like target, key, etc.).onClick, onInput, etc. β use clickEvent, inputEvent, etc. instead.if / else if / else and forEach for dynamic UI behavior.CSS directives provide a way to make component styling more flexible and maintainable by supporting variable substitution and scoped customization. They enable styles to adapt dynamically at runtime without breaking encapsulation.
Template interpolation enables the embedding of JavaScript expressions directly within CSS content, using the ${this.expression} syntax.
This works similarly to HTML template interpolation, allowing you to bind JavaScript properties or return values directly into your styles at render time.
Expressions must be valid JavaScript and scoped to the current component (this.property or this.method()).
Only values that result in a valid CSS value are allowed (colors, units, keywords).
Function calls must return a value and must be pure (no side effects).
You can interpolate in inline styles, style blocks, or custom properties (e.g., --my-color: $ {this.color}).
Do not use interpolation inside CSS selectors or media queries, only in property values.
Keep expressions simple and readable. Avoid chaining or complex logic inside styles.
Inspector View (Elements)
--theme-accent: $ {this.accentColor}.The framework includes a lightweight Observable utility for managing event-based communication between components or logic blocks. This pattern allows you to decouple parts of your application by subscribing to and publishing named events, similar to a pub/sub model.
subscribe(name, subscriber): Register a function to run when a named event is published.
unsubscribe(name): Remove a previously registered event handler.
publish(name, payload): Trigger all subscriber callbacks for the given event name, passing in an optional payload.
Each event supports a single active subscriber, subsequent calls with the same name will replace previous ones.
The Observable system can be used for reactive data handling, custom event broadcasting, or integrating cross-component behaviors in a clean, manageable way.
HTMLComponent class with Shadow DOM support.preProcess() β toProcess() β atProcess() β inProcess().lazyLoading.app.config.json.Dom.init() for unified initialization.if, else if, else and forEach directive availaible in the HTML template..apendToBody.