v1.0.0

HTML components.
Zero runtime.

What if you could have components that were just HTML files without any special syntax? Now you can. Bascik is a build tool for HTML components with automatically scoped CSS and JS. Zero runtime. The code that ships is the code you wrote.

npm create bascik@latest

Write your code. Bascik does the rest.

Create a file with your component name. Add your HTML, CSS, and JavaScript. Reference that tag in any page or component with no imports or configuration needed.

my-card
html
<!-- src/pages/index.html -->
<!DOCTYPE html>
<html lang="en">
<body>
  <my-card>
    <h3>My Card</h3>
    <p>Any HTML goes inside as slot content.</p>
  </my-card>
</body>
</html>
html
<!-- src/components/my-card.html -->
<style>
  .card {
    padding: 24px 28px;
    border: 1px solid #3a3d40;
    border-top: 3px solid #d3ff8d;
    border-radius: 10px;
  }
</style>
<article class="card">
  <div data-bascik-slot></div>
</article>
Output is shown unminified (HTML, CSS, JS, and identifier names) for readability.
html
<!-- dist/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    .bascik__my-card__card {
      padding: 24px 28px;
      border: 1px solid #3a3d40;
      border-top: 3px solid #d3ff8d;
      border-radius: 10px;
    }
  </style>
</head>
<body>
  <article class="bascik__my-card__card">
    <h3>My Card</h3>
    <p>Any HTML goes inside as slot content.</p>
  </article>
</body>
</html>

Live Example

My Card

Any HTML goes inside as slot content.

Sub-second build speeds. Industry-leading performance.

Bascik transpiles and scopes entire static websites in milliseconds. This documentation website is a prime example: every single one of its 50 pages executes custom Node.js build-time scripts to convert Markdown, extract code blocks, and construct structured search schemas, yet, on a 2020 M1 MacBook Air, the entire site compiles in under 1.8 seconds.

yarn docs:dev
text
$ bascik
transpiled: pages/404.html
transpiled: pages/index.html
transpiled: pages/search.html
transpiled: pages/license.html
transpiled: pages/getting-started.html
...
✓ 50 pages transpiled in 1779ms
Server running at http://localhost:8080
1779ms
50 full pages transpiled with build scripts, search indexing, and component scoping
~35ms
Average build time per page
0 kB
Framework runtime overhead

One component. Two isolated instances.

Bascik scopes CSS class names and DOM selectors at build time. Each instance gets its own namespace with no runtime JS, no Shadow DOM, and no virtual DOM.

demo-counter
html
<!-- src/pages/index.html -->
<!DOCTYPE html>
<html lang="en">
<body>
  <demo-counter data-bascik-prop-label="Instance A" />
  <demo-counter data-bascik-prop-label="Instance B" />
</body>
</html>
html
<!-- src/components/demo-counter/demo-counter.html -->
<div class="ctr">
  <span class="ctr-label" data-bascik-prop-label>
    Counter
  </span>
  <span class="ctr-count" id="count">0</span>
  <div class="ctr-btns">
    <button class="ctr-dec" id="dec">−</button>
    <button class="ctr-inc" id="inc">+</button>
  </div>
</div>
<script src="demo-counter.ts"></script>
css
/* src/components/demo-counter/demo-counter.css */
.ctr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.ctr-count {
  font-size: 2.4rem;
  font-weight: 700;
  color: #d3ff8d;
}
.ctr-dec, .ctr-inc {
  width: 40px;
  height: 40px;
  border-radius: 6px;
  cursor: pointer;
}
ts
// src/components/demo-counter/demo-counter.ts
const count = document.getElementById('count') as HTMLElement;
const dec   = document.getElementById('dec') as HTMLButtonElement;
const inc   = document.getElementById('inc') as HTMLButtonElement;
let n: number = 0;

dec.addEventListener('click', () => {
  n--;
  count.textContent = String(n);
});
inc.addEventListener('click', () => {
  n++;
  count.textContent = String(n);
});
Output is shown unminified (HTML, CSS, JS, and identifier names) for readability.
html
<!-- dist/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    .bascik__demo-counter__ctr {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 16px;
    }
    .bascik__demo-counter__ctr-count {
      font-size: 2.4rem;
      font-weight: 700;
      color: #d3ff8d;
    }
    .bascik__demo-counter__ctr-dec,
    .bascik__demo-counter__ctr-inc {
      width: 40px;
      height: 40px;
      border-radius: 6px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="bascik__demo-counter__ctr">
    <span class="bascik__demo-counter__ctr-label">Instance A</span>
    <span class="bascik__demo-counter__ctr-count"
          id="bascik__demo-counter__a1b2__count">0</span>
    <div class="bascik__demo-counter__ctr-btns">
      <button class="bascik__demo-counter__ctr-dec"
              id="bascik__demo-counter__a1b2__dec">−</button>
      <button class="bascik__demo-counter__ctr-inc"
              id="bascik__demo-counter__a1b2__inc">+</button>
    </div>
  </div>
  <script>
    (function() {
      const count = document.getElementById("bascik__demo-counter__a1b2__count");
      const dec   = document.getElementById("bascik__demo-counter__a1b2__dec");
      const inc   = document.getElementById("bascik__demo-counter__a1b2__inc");
      let n = 0;
      dec.addEventListener("click", () => { n--; count.textContent = String(n); });
      inc.addEventListener("click", () => { n++; count.textContent = String(n); });
    })();
  </script>
</body>
</html>
Multiple instances of a component on the same page
Instance A 0
Instance B 0

Built for developer joy.

Component modularity and automatic scoping without the framework friction, complex setups, or runtime overhead.

Zero Configuration

Works instantly

No bundler setups, complex configs, or transpiler chains. Run bascik and start building instantly with standard Node.js.

Zero Learning Curve

Standard HTML & CSS

No JSX, custom template syntax, or framework hooks. Write pure HTML and CSS with standard DOM APIs—everything you know just works.

Zero Runtime Overhead

Automatic isolation

Component styles and DOM queries are scoped automatically at build time. Enjoy total component isolation with zero added JavaScript.

Up and running in under a minute.

One command scaffolds your project and starts the dev server. No config required to get going.

$ npm create bascik@latest
Read the Getting Started Guide →