HTML components.
Zero runtime.
There's times where you just want to reuse a component like a nav on every page, and not need a whole framework. Bascik solves that problem. Create a file, the filename is the component name. Add CSS and JS inside the file, that gets scoped automatically. Then simply reference that component name in your page as an HTML tag.
npm create bascik@latestHow it works
You write the HTML. Bascik scopes it.
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.
<!-- src/components/my-card.html -->
<style>
.card {
padding: 26px 28px;
background: #1e2022;
border: 1px solid rgba(255,255,255,0.08);
border-radius: 10px;
h3 { margin: 0 0 8px; color: #f0f1f2; }
p { margin: 0; color: #8d929e; }
}
</style>
<div class="card" id="card">
<div data-bascik-slot></div>
</div>
<script>
const card = document.getElementById('card');
card.addEventListener('click', () => {
card.classList.toggle('active');
});
</script> <!-- src/pages/index.html -->
<my-card>
<h3>My Card</h3>
<p>Any HTML goes inside as slot content.</p>
</my-card> <!-- dist/index.html - CSS classes and JS selectors scoped -->
<style>
.bascik__my-card__card {
padding: 26px 28px;
background: #1e2022;
border: 1px solid rgba(255,255,255,0.08);
border-radius: 10px;
h3 { margin: 0 0 8px; color: #f0f1f2; }
p { margin: 0; color: #8d929e; }
}
</style>
<div class="bascik__my-card__card" id="bascik__my-card__a1b__card">
<h3>My Card</h3>
<p>Any HTML goes inside as slot content.</p>
</div>
<script>
(function(){
const card = document.getElementById('bascik__my-card__a1b__card');
card.addEventListener('click', () => {
card.classList.toggle('bascik__my-card__active');
});
})();
</script>Live render
My Card
Any HTML goes inside as slot content. Click to toggle state.
Demo
One component. Two isolated instances.
Bascik scopes CSS class names and DOM selectors at build time. Each component instance gets its own namespace with no runtime and no Shadow DOM.
<!-- src/components/demo-counter.html - component template -->
<div class="ctr">
<span class="ctr-label"
data-bascik-prop-label></span>
<span class="ctr-count" id="count">0</span>
<div class="ctr-btns">
<button class="ctr-dec">−</button>
<button class="ctr-inc">+</button>
</div>
</div>
<!-- src/pages/index.html - usage -->
<demo-counter data-bascik-prop-label="Instance A"></demo-counter>
<demo-counter data-bascik-prop-label="Instance B"></demo-counter>/* Auto-scoped - class names become:
.bascik__demo-counter__ctr { ... } */
.ctr { display: flex; flex-direction: column;
align-items: center; gap: 16px; }
.ctr-count {
font-size: 2.4rem; font-weight: 700;
color: var(--accent);
}
.ctr-dec, .ctr-inc {
width: 40px; height: 40px;
border-radius: 6px; cursor: pointer;
}// Notice: this is plain JavaScript. No framework APIs,
// no special syntax. Write it normally and Bascik
// scopes the selectors at build time so each instance
// stays fully isolated.
const count = document.getElementById('count');
const dec = document.querySelector('.ctr-dec');
const inc = document.querySelector('.ctr-inc');
let n = 0;
dec.addEventListener('click', () => {
n--; count.textContent = n;
});
inc.addEventListener('click', () => {
n++; count.textContent = n;
});Philosophy
Use what already exists.
The principle behind every decision Bascik makes: no inventions, no abstractions you have to learn.
No JS added
Zero runtime footprint
Bascik adds no JavaScript to your output. Every script in dist/ was written by you. What you ship is exactly what you wrote.
Build-time scoping
No CSS collisions. Ever.
Class names and DOM selectors are rewritten at build time. No CSS-in-JS, no BEM discipline, no global namespace to manage.
Standard HTML
Nothing new to learn
No JSX, no template syntax, no special compiler directives. Write the HTML you already know. Bascik does the assembly.
Docs
Explore the docs.
Each feature has a dedicated page with examples and a complete reference.
CSS
Scoped Styles
Class names, element selectors, @media, and @keyframes are all automatically scoped per component.
JS
Scoped JavaScript
DOM queries in component scripts are rewritten to match scoped IDs and class names at build time.
Slots
Default & Named Slots
Pass inner HTML into components. Named slots target specific zones with fallback content supported.
Props
Component Props
Inject text values via data-bascik-prop-* attributes, with no runtime and no special syntax.
Build
Build Scripts
Run arbitrary Node.js at build time with data-bascik-build script blocks. Fetch data, render Markdown, generate anything.
Config
Configuration
Override defaults in bascik.config.js. Toggle scoping, obfuscation, and minification per project.
Reference
Scoping Compatibility
A complete audit of which CSS selectors and JS DOM patterns are scoped, partial, or unsupported.
Migration
Migration Guides
Moving from React, Next.js, Eleventy, or Astro. Concept mapping and worked examples.
Ready to build?
Up and running in under a minute.
One command scaffolds your project and starts the dev server. No config required to get going.