Skip to content
Andre Kless edited this page Dec 31, 2025 · 97 revisions

Overview

The Client-side Component Model (CCM) defines a conceptual framework for developing modular and reusable web components. The ccmjs framework provides the official JavaScript reference implementation of this model.

Differentiation

While W3C Web Components focus on extending HTML, ccmjs focuses on JavaScript-based composition and JSON-driven configuration.

Unlike frameworks such as Angular, React, or Vue, ccmjs composes components at runtime. Components are loaded, configured, and instantiated dynamically in the browser — without a build step or bundler, and without prior compilation.

ccmjs components are configured via declarative data and resolve their dependencies on demand. This enables highly dynamic applications where structure and behavior can change at runtime.

Basic Principle

With the JavaScript command ccm.start(component, config, area), a component (component) with a specific configuration (config) can be embedded in a web page area (area). The combination of the component and its configuration results in a concrete application instance, which is then rendered into the specified area of the web page.

As soon as ccmjs is integrated into a web page, ccm.start() is available. Here is an example of embedding a quiz app:

<!DOCTYPE html>
<meta charset="UTF-8">
<body>
<script src="https://ccmjs.github.io/framework/ccm.js"></script>
<script>
  ccm.start("https://ccmjs.github.io/quiz/ccm.quiz.mjs", {
    feedback: true,
    questions: [
      {
        text: "Does this example work?",
        input: "radio",
        answers: [
          {text: "Yes", correct: true},
          {text: "No"}
        ]
      }
    ]
  }, document.body);
</script>

Structure of a Component

A component is a file whose name starts with ccm., followed by the component's unique name and ends with .mjs. Example: ccm.quiz.mjs.

The content of a component has the following structure:

export const component = {
  name: "quiz",                                    // unique name
  ccm: "https://ccmjs.github.io/framework/ccm.js", // URL to ccmjs
  config: {/*...*/},                               // contains the default configuration
  Instance: function () {
    this.start = async () => {/*...*/};            // the web page area of ​​the component is designed here
  }
};

Within the start() the web page area to be designed can be accessed with this.element. Every entry in the config can be accessed via this.

Example of a hello component:

export const component = {
  name: "hello",
  ccm: "https://ccmjs.github.io/framework/ccm.js",
  config: {
    name: "World"
  },
  Instance: function () {
    this.start = async () => {
      this.element.innerHTML = "Hello " + this.name;
    };
  }
};

Usage of the hello component:

<!DOCTYPE html>
<meta charset="UTF-8">
<body>
<script src="https://ccmjs.github.io/framework/ccm.js"></script>
<script>
  ccm.start("./ccm.hello.mjs", {
    name: "Mika"                 // overrides "World" in the default configuration
  }, document.body);
</script>

The <body> of the web page then contains Hello Mika.

Services

ccmjs offers the following services:

In addition, ccmjs also offers useful Helper Functions for component developers under ccm.helper.

Integration of Resources

Additional dependent resources can be dynamically integrated at runtime via the config of a component. Dependencies to other resources are specified as an array in the form of [functionName, ...params]. Examples:

const config = {
  html: ["ccm.load", "./templates.html"],                       // HTML templates
  css: ["ccm.load", "./styles.css"],                            // CSS
  store: ["ccm.store", {name: "mycollection"}],                 // datastore
  dataset: ["ccm.get", {name: "mycollection"}, "mykey"],        // single dataset
  comp: ["ccm.component", "./ccm.component.mjs", {/*config*/}], // component object
  inst: ["ccm.instance", "./ccm.component.mjs", {/*config*/}],  // instance of a component
  app: ["ccm.start", "./ccm.component.mjs", {/*config*/}]       // directly started instance
};

Dependencies in CCM are expressed declaratively and resolved automatically at runtime.

Design Philosophy

ccmjs intentionally keeps its core minimal. Common concerns such as Routing, User Authentication, or Internationalization are not built into the framework itself. Instead, they are provided as optional ccmjs components that can be added via configuration when needed.

Similarly, ccmjs does not prescribe a specific HTML Templating system. Component developers are free to choose how rendering is implemented. For convenience, ccmjs offers optional utilities such as <ccm-template> for HTML templates and JSON-based HTML representation, which can be used but are not required.

In addition to JavaScript-based embedding, ccmjs also supports declarative component embedding via HTML:

<!DOCTYPE html>
<meta charset="UTF-8">
<body>
<script src="https://ccmjs.github.io/framework/ccm.js"></script>
<ccm-app component="./ccm.hello.mjs" config='{"name":"Mika"}'></ccm-app>

This feature is optional and intended as a convenience mechanism. The primary and recommended interaction model of CCM remains explicit embedding via JavaScript (ccm.start()), which enables dynamic composition, runtime configuration, and full programmatic control.

Versioning and Isolation are core design principles of ccmjs. Both the framework and CCM components are explicitly versioned, allowing multiple framework versions and multiple versions of the same component to safely coexist on the same web page. Each component is bound to a specific ccmjs version and executes within its own namespace, preventing global conflicts and enabling independent evolution.

Clone this wiki locally