# kt.js v0.5.x
[](https://www.npmjs.com/package/kt.js) [](https://github.com/baendlorel/kt.js/blob/main/LICENSE)
[CHANGLOG✨](CHANGELOG.md)
> Note: This framework is still under development. APIs, type declarations, and other parts **may change frequently**. If you use it, please watch for updates in the near future. Feel free to mail me if you have any questions!
KT.js is a tiny DOM utility focused on direct DOM manipulation. It favors not forcing re-renders and aims to keep DOM updates to the absolute minimum for maximum performance.
For more awesome packages, check out [my homepage💛](https://baendlorel.github.io/?repoType=npm)
## Architecture
KT.js is now a **monorepo** containing multiple packages:
- **[@ktjs/core](./packages/core)**: Core DOM manipulation utilities and the `h` function
- **[@ktjs/router](./packages/router)**: Client-side routing with navigation guards (not included in kt.js package)
- **[@ktjs/shortcuts](./packages/shortcuts)**: Convenient shortcut functions for common operations
- **[kt.js](./packages/kt.js)**: Main entry package that re-exports all functionality
You can install the full package or individual packages as needed:
```bash
# Install the main package (includes core + shortcuts)
pnpm add kt.js
# Or install individual packages
pnpm add @ktjs/core # Core DOM utilities (independent)
pnpm add @ktjs/router # Client-side router (independent)
pnpm add @ktjs/shortcuts # Shortcuts (requires @ktjs/core)
```
## Philosophy
As a web framework, repeatedly creating a large number of variables and objects is unacceptable. So I created KT.js.
KT.js follows one rule: **full control of DOM and avoid unnecessary repainting**.
## Key Features
- **Monorepo Architecture**: Modular packages that can be installed independently or together
- **Tiny Bundle Size**: Minimal runtime overhead with aggressive tree-shaking
- **`h` function**: Create DOM elements with a simple, flexible API
- Shortcut functions for all HTML elements (`div`, `span`, `button`, etc.)
- Event handlers with `@` syntax or function attributes
- Full TypeScript support with intelligent type inference
- **Client-Side Router** (separate package):
- Hash-based routing with dynamic parameters
- Navigation guards with async/sync auto-adaptation
- Query string parsing and route matching
- Pure routing logic - no rendering, no dependencies
- **Shortcuts & Utilities**:
- `withDefaults`: Wrap element creation functions with default properties
- Convenient shorthand functions for common operations
- Form helpers and layout utilities
- **Full ES5 Compatibility**: Works in IE9+ and all modern browsers
- Transpiled to ES5 with no modern syntax
- Optional minimal Promise polyfill for older environments
- **`ktnull`**: A special value for filtering null/undefined while preserving native DOM behavior
- **Shared Runtime**: Efficient code sharing across packages with zero overhead
## Getting started
Install via package managers:
```bash
npm install kt.js
# or
pnpm add kt.js
```
```ts
import { h, div } from 'kt.js';
const container = div('container', [div('header'), div('body', 'something'), div('footer')]);
const app = h('section', { id: 'app' }, container);
```
This will create the following DOM structure:
```html
```
If you give a function in attributes, it will be treated as an event listener, and the key will be considered as the event name. `@` will also be considered as the handler to avoid conflicts with existing attributes:
```ts
const button = btn(
{
click: () => alert('Clicked!'),
dblclick: '22',
'@dblclick': function trueHandler() {
/* ... */
},
},
'Click me'
);
// This is equivalent to:
const button = btn(undefined, 'Click me');
button.setAttribute('dblclick', '22');
button.addEventListener('click', () => alert('Clicked!'));
button.addEventListener('dblclick', function trueHandler() {
/* ... */
});
```
### Working with CSS-in-JS Libraries
KT.js works seamlessly with CSS-in-JS libraries like `@emotion/css`:
```ts
import { css } from '@emotion/css';
import { h, div } from 'kt.js';
const className = css`
color: red;
font-size: 20px;
`;
// Pass class name as attribute
h('div', { class: className }, 'Styled text');
// Or as the first string argument
div(className, 'Styled text');
```
### Using Shortcuts with Default Values
The `withDefaults` function allows you to create element factories with predefined properties:
```ts
import { withDefaults, div, button } from 'kt.js';
// Create a styled div factory
const card = withDefaults(div, { class: 'card' });
const blueCard = withDefaults(card, { style: 'background: blue' });
// Use them
const myCard = card('card-body', 'Content'); //
const myBlueCard = blueCard('title', 'Blue!'); //
```
## Router
The router is available as a separate package `@ktjs/router`:
```ts
import { createRouter } from '@ktjs/router';
import { div, h1 } from 'kt.js';
const router = createRouter({
routes: [
{
path: '/',
name: 'home',
beforeEnter: (to) => {
// Render your page here
document.getElementById('app')!.innerHTML = '';
document.getElementById('app')!.appendChild(
div({}, [h1({}, 'Home Page')])
);
},
},
{
path: '/user/:id',
name: 'user',
beforeEnter: (to) => {
// Route-specific guard and rendering
console.log('Entering user page');
document.getElementById('app')!.innerHTML = '';
document.getElementById('app')!.appendChild(
div({}, [h1({}, `User ${to.params.id}`)])
);
return true;
},
},
],
beforeEach: async (to, from) => {
// Global navigation guard - return false to block navigation
console.log('Navigating to:', to.path);
return true;
},
afterEach: (to) => {
// Called after successful navigation
document.title = to.name || to.path;
},
onError: (error) => {
console.error('Router error:', error);
},
});
// Navigate programmatically
router.push('/user/123');
router.push('/user/456?page=2');
// Navigate by route name
router.push({ name: 'user', params: { id: '789' } });
// Get current route
console.log(router.current?.path, router.current?.params, router.current?.query);
```
### Router Features
- **Hash-based Routing**: Uses URL hash for client-side navigation (`#/path`)
- **Dynamic Parameters**: Support for dynamic route segments (`/user/:id`)
- **Query Strings**: Automatic parsing of query parameters (`?key=value`)
- **Named Routes**: Navigate using route names instead of paths
- **Navigation Guards**:
- `beforeEach`: Global guard before navigation
- `beforeEnter`: Per-route guard (can also be used for rendering)
- `afterEach`: Global hook after navigation
- `after`: Per-route hook after navigation
- Async support with automatic sync fallback for non-Promise environments
- `GuardLevel` for fine-grained control over guard execution
- **Error Handling**: `onError` and `onNotFound` callbacks
- **Optimized Performance**: Pre-flattened routes and efficient matching algorithm
- **Zero Dependencies**: Fully self-contained router implementation (does not require `@ktjs/core` for runtime, only for TypeScript types)
- **Pure Routing**: No rendering logic - you control the DOM
## `ktnull`
`ktnull`, assigned by `Object.create(null)`, is a falsy value.
It is used for filtering, you can do like this:
```ts
import { div, ktnull } from 'kt.js';
const list = div('', [false ? div('', 'item 1') : ktnull, div('', 'Item 2'), undefined]);
```
Then it will create:
```html
```
## Browser Compatibility
KT.js is transpiled to ES5 and works in all modern browsers as well as legacy browsers including IE9+.
### Promise Polyfill
For environments without native `Promise` support (like IE).
```js
import 'some promise polyfill'; // Will fallback to sync version if Promise is not available
import { h, div, createRouter } from 'kt.js';
```
## License
MIT