https://github.com/navilan/duct-ui
An experimental framework / library for building dynamic user interfaces
https://github.com/navilan/duct-ui
Last synced: 10 months ago
JSON representation
An experimental framework / library for building dynamic user interfaces
- Host: GitHub
- URL: https://github.com/navilan/duct-ui
- Owner: navilan
- Created: 2025-07-16T11:48:14.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-08-10T20:45:32.000Z (10 months ago)
- Last Synced: 2025-08-10T22:22:14.788Z (10 months ago)
- Language: TypeScript
- Homepage: https://duct-ui.org
- Size: 1.52 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Duct UI

A DOM-first UI framework with JSX templates, standard component library and explicit lifecycle management.
> **⚠️ Under Construction**: This library is currently in early development and may exhibit unexpected behavior. APIs are subject to change and components may not be fully stable. Use with caution in production environments.
## Quick Start
```bash
npm install @duct-ui/core @duct-ui/components
```
```typescript
import { createRef } from '@duct-ui/core'
import Button from '@duct-ui/components/button/button'
const buttonRef = createRef()
function MyApp() {
return (
console.log('Clicked!')}
/>
)
}
```
## Core Concepts
### Component Logic Access
Access component methods via refs:
```typescript
const buttonRef = createRef()
// In render
// Access methods
buttonRef.current?.setDisabled(true)
```
### Lifecycle Phases
Components follow explicit lifecycle phases:
1. **Render**: JSX structure creation
2. **Load**: Async data loading (optional)
3. **Bind**: Event listeners and logic setup
4. **Release**: Cleanup when component unmounts
## Building Components
```typescript
import { createBlueprint, type BaseProps, type BaseComponentEvents } from '@duct-ui/core'
interface MyComponentProps {
label: string
disabled?: boolean
'on:click'?: (el: HTMLElement) => void
}
interface MyComponentEvents extends BaseComponentEvents {
click: (el: HTMLElement) => void
}
interface MyComponentLogic {
setDisabled: (disabled: boolean) => void
}
function render(props: BaseProps) {
const { disabled = false, label, ...moreProps} = props;
return (
{label}
)
}
function bind(el: HTMLElement, eventEmitter, props): BindReturn {
const button = el as HTMLButtonElement
function handleClick() {
eventEmitter.emit('click', button)
}
button.addEventListener('click', handleClick)
return {
setDisabled: (disabled) => button.disabled = disabled,
release: () => button.removeEventListener('click', handleClick)
}
}
const MyComponent = createBlueprint(
{ id: 'my-app/my-component' },
render,
{ bind }
)
export default MyComponent
```
## Packages
- **@duct-ui/core**: Core framework runtime and utilities
- **@duct-ui/components**: Pre-built component library
- **@duct-ui/cli**: Static site generation and build tools
- **@duct-ui/demo**: Interactive demos and documentation
## Static Site Generation
Duct includes first-class support for static site generation with file-based routing:
```bash
npm install @duct-ui/cli --save-dev
```
Build fast, SEO-friendly static sites with Duct components using file-based routing, dynamic routes, and Nunjucks layouts. Perfect for documentation sites, blogs, and marketing pages.
[→ Learn more about SSG](https://duct-ui.org/docs/static-site-generation)
## Philosophy
1. **Don't hide the DOM** - Direct DOM access and manipulation
2. **Little magic, lots of logic** - Explicit over implicit
3. **Easy packaging, simple reuse** - Component composition and distribution