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.
npm install @duct-ui/core @duct-ui/components
import { createRef } from '@duct-ui/core'
import Button from '@duct-ui/components/button/button'
const buttonRef = createRef<ButtonLogic>()
function MyApp() {
return (
<Button
ref={buttonRef}
label="Click me"
class="btn btn-primary"
on:click={() => console.log('Clicked!')}
/>
)
}
Access component methods via refs:
const buttonRef = createRef<ButtonLogic>()
// In render
<Button ref={buttonRef} label="Toggle" />
// Access methods
buttonRef.current?.setDisabled(true)
Components follow explicit lifecycle phases:
- Render: JSX structure creation
- Load: Async data loading (optional)
- Bind: Event listeners and logic setup
- Release: Cleanup when component unmounts
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<MyComponentProps>) {
const { disabled = false, label, ...moreProps} = props;
return (
<button
class="btn"
disabled={disabled}
{...moreProps}
>
{label}
</button>
)
}
function bind(el: HTMLElement, eventEmitter, props): BindReturn<MyComponentLogic> {
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<MyComponentProps, MyComponentEvents, MyComponentLogic>(
{ id: 'my-app/my-component' },
render,
{ bind }
)
export default MyComponent
- @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
Duct includes first-class support for static site generation with file-based routing:
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.
- Don't hide the DOM - Direct DOM access and manipulation
- Little magic, lots of logic - Explicit over implicit
- Easy packaging, simple reuse - Component composition and distribution