https://github.com/praxisjs-org/praxisjs
Signal-driven frontend framework written in TypeScript, combining fine-grained reactivity, class components, and decorators in a complete first-party ecosystem.
https://github.com/praxisjs-org/praxisjs
class-components decorators dependency-injection devtools frontend-framework jsx no-virtual-dom praxisjs reactivity router signals state-management typescript vite web-framework
Last synced: 20 days ago
JSON representation
Signal-driven frontend framework written in TypeScript, combining fine-grained reactivity, class components, and decorators in a complete first-party ecosystem.
- Host: GitHub
- URL: https://github.com/praxisjs-org/praxisjs
- Owner: praxisjs-org
- License: mit
- Created: 2026-03-01T14:56:46.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-06-03T17:12:58.000Z (23 days ago)
- Last Synced: 2026-06-03T19:08:06.723Z (23 days ago)
- Topics: class-components, decorators, dependency-injection, devtools, frontend-framework, jsx, no-virtual-dom, praxisjs, reactivity, router, signals, state-management, typescript, vite, web-framework
- Language: TypeScript
- Homepage: https://praxisjs.org/
- Size: 12 MB
- Stars: 6
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

# PraxisJS
**Signal-driven TypeScript frontend framework.**
Fine-grained reactivity · Decorator-first class components · Complete ecosystem
[](https://www.npmjs.com/package/@praxisjs/core)
[](https://codecov.io/gh/praxisjs-org/praxisjs)
[](./LICENSE)
[Docs](https://praxisjs.org) · [Getting Started](https://praxisjs.org/docs/guide/getting-started) · [Changelog](https://praxisjs.org/docs/changelog)
---
PraxisJS is a TypeScript frontend framework built around a fine-grained signal engine. Components are plain classes decorated with a rich built-in decorator set — no hooks, no magic strings, no virtual DOM. The first-party ecosystem covers routing, global state, animations, dependency injection, finite state machines, async data, and more.
## Quick look
```tsx
import { Component, State, Watch, Resource } from '@praxisjs/decorators'
import type { ResourceInstance } from '@praxisjs/decorators'
import { StatefulComponent } from '@praxisjs/core'
interface Post { id: number; title: string }
@Component()
class BlogPage extends StatefulComponent {
@State() page = 1
@Resource((self: BlogPage) =>
fetch(`/api/posts?page=${self.page}`).then(r => r.json() as Promise)
)
posts!: ResourceInstance
@Watch('page')
onPageChange(next: number) {
window.scrollTo(0, 0)
}
render() {
return (
{() => this.posts.pending() && Loading…
}
{() => this.posts.data()?.map(p => {p.title}
)}
this.page++}>Next page
)
}
}
```
Changing `this.page` automatically cancels the previous request and starts a new one — no `useEffect`, no manual cleanup.
## Packages
### Foundation
| Package | Version | Description |
|---|---|---|
| [`@praxisjs/core`](packages/foundation/core) | `1.7.0` | Signal engine — `signal`, `computed`, `effect`, `batch`, `resource` |
| [`@praxisjs/decorators`](packages/foundation/decorators) | `1.1.0` | Class component decorators — `@State`, `@Prop`, `@Watch`, `@Emit`, `@Resource`, `@Memo`, … |
| [`@praxisjs/runtime`](packages/foundation/runtime) | `0.3.0` | DOM renderer, scope system, `Portal` |
| [`@praxisjs/jsx`](packages/foundation/jsx) | `0.5.0` | JSX runtime (`jsx-runtime`, `jsx-dev-runtime`) |
| [`@praxisjs/shared`](packages/foundation/shared) | `0.2.0` | Shared types and internal utilities |
```sh
npm install @praxisjs/core @praxisjs/decorators @praxisjs/runtime @praxisjs/jsx
```
### Features
| Package | Version | Description |
|---|---|---|
| [`@praxisjs/router`](packages/features/router) | `1.2.0` | Client-side router — `@Router`, `@Route`, `@Lazy`, layouts, navigation guards |
| [`@praxisjs/store`](packages/features/store) | `1.2.0` | Global reactive state — `@Storable`, `@Store` |
| [`@praxisjs/di`](packages/features/di) | `1.3.0` | Dependency injection — `Container`, `@Inject`, `@Injectable` |
| [`@praxisjs/motion`](packages/features/motion) | `1.1.11` | Animations — `@Tween`, `@Spring` |
| [`@praxisjs/fsm`](packages/features/fsm) | `2.0.0` | Finite state machines — `@StateMachine`, `@Transition` |
| [`@praxisjs/head`](packages/features/head) | `0.2.0` | Reactive document head — `@Head` for title, meta, og:*, twitter:* |
| [`@praxisjs/content`](packages/features/content) | `0.1.0` | Markdown content collections — `@Collection`, `@PagedCollection` |
### Utilities
| Package | Version | Description |
|---|---|---|
| [`@praxisjs/composables`](packages/utils/composables) | `1.1.2` | Class-based composables — `WindowSize`, `ScrollPosition`, `Focus`, … |
| [`@praxisjs/concurrent`](packages/utils/concurrent) | `1.2.9` | Async concurrency — `@Task`, `@Queue`, `@Pool` |
### DX
| Package | Version | Description |
|---|---|---|
| [`@praxisjs/vite-plugin`](packages/dx/vite-plugin) | `0.1.1` | Vite integration — JSX transform, decorator support, HMR |
| [`@praxisjs/devtools`](packages/dx/devtools) | `0.2.19` | In-app signal inspector and component profiler |
| [`@praxisjs/storybook`](packages/dx/storybook) | `0.1.1` | Storybook framework adapter |
| [`@praxisjs/mcp`](packages/dx/mcp) | `0.1.0` | MCP server for AI assistant integration |
| [`create-praxisjs`](packages/create-praxisjs) | `0.4.2` | Project scaffolding CLI |
```sh
npm create praxisjs@latest
```
## Monorepo layout
```
packages/
foundation/ core · shared · decorators · jsx · runtime
features/ router · store · di · motion · fsm · head · content
utils/ composables · concurrent
dx/ vite-plugin · devtools · storybook · mcp
create-praxisjs/
playground/ manual testing app (Vite)
docs/ documentation site (Next.js + Fumadocs)
```
## Development
Requires [pnpm](https://pnpm.io).
```sh
pnpm install
# build everything (required before first run)
pnpm build
# build by layer
pnpm build:foundation
pnpm build:features
pnpm build:utils
pnpm build:dx
# watch mode — rebuild all packages on change
pnpm dev
# playground (hot-reload manual test app)
pnpm --filter playground dev
# tests
pnpm test
pnpm test:watch
pnpm test:coverage
# lint + typecheck
pnpm lint
pnpm lint:fix
pnpm typecheck
# docs dev server
pnpm docs:dev
```
> After editing a package's source, rebuild it before dependent packages pick up the change:
> `pnpm --filter @praxisjs/core build`
## Releases
Changesets — pick affected packages, bump type, and summary:
```sh
pnpm changeset # interactive — create a changeset
pnpm version-packages # bump versions + sync create-praxisjs templates
pnpm release # publish to npm
```
## Contributing
PraxisJS is a personal project built out of curiosity and a desire to explore framework design from scratch. Contributions are welcome — bug reports, ideas, and pull requests. Opening an issue before a large change is appreciated.
## License
[MIT](./LICENSE)