@obinexusltd/obix-jsx-components
v0.1.2
Published
JSX factory functions for all 30 OBIX components — wraps obix-component-runtime
Maintainers
Readme
@obinexusltd/obix-jsx-components
JSX Factory Functions for 30 OBIX UI Components
Overview
@obinexusltd/obix-jsx-components provides 30 production-ready JSX component factories that compile to pure OBIX data objects. No virtual DOM. No framework dependencies. Just plain HTML/CSS/JS.
Core Philosophy
JSX is syntax sugar. Components are data objects.
// JSX Input (React specification-compliant)
<obix-button label="Save" variant="primary" />
// ↓ (TypeScript compiler)
// Function Call (intermediate)
h(obixButton, { label: "Save", variant: "primary" })
// ↓ (@obinexusltd/obix-jsx-adapter)
// Data Object (OBIX runtime)
{
name: 'Button',
state: { label: 'Save', variant: 'primary', ... },
actions: { setLabel, setDisabled, ... },
render: (state) => '<button>Save</button>',
aria: { ... }
}Features
30 Components Organized by Category
| Category | Components | |----------|-----------| | Primitives | button, card, image, video, link | | Forms | input, checkbox, radio-group, select, textarea, form, date-picker, file-upload | | Navigation | navigation, breadcrumb, pagination, tabs, stepper | | Overlays | modal, dropdown, tooltip | | Feedback | alert, toast, progress, loading | | Controls | slider, switch | | Data | table, accordion | | Search | search, autocomplete |
Benefits
✅ Framework-Agnostic — Works in vanilla JS, React, Vue, SSR, HTMX, Svelte
✅ Type-Safe — Full TypeScript support with JSX compilation
✅ Accessibility First — WCAG 2.1 AA compliant by default
✅ Immutable State — Pure functions for predictable rendering
✅ Server-Renderable — No DOM needed, just .render(state) → HTML string
✅ Non-Monolithic — Paradigm-agnostic, works with Functional/OOP/Reactive adapters
✅ Zero Dependencies — Only depends on obix-component-runtime and obix-jsx-adapter
✅ Tested — Unit + render + integration tests for every component
Installation
npm install @obinexusltd/obix-jsx-components
npm install @obinexusltd/obix-jsx-adapter # Required peer
npm install @obinexusltd/obix-component-runtime # Required peerTypeScript Configuration
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment",
"target": "ES2020",
"module": "ESNext",
"strict": true
}
}Quick Start
1. Vanilla JavaScript (No Build Step)
<!DOCTYPE html>
<html>
<head>
<title>OBIX JSX Demo</title>
</head>
<body>
<div id="app"></div>
<script type="module">
import { h } from '@obinexusltd/obix-jsx-adapter';
import { obixButton } from '@obinexusltd/obix-jsx-components';
const button = h(obixButton, { label: 'Click Me', variant: 'primary' });
document.getElementById('app').innerHTML = button.render(button.state);
</script>
</body>
</html>2. TypeScript with JSX Syntax
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from '@obinexusltd/obix-jsx-adapter';
import { obixForm, obixInput, obixButton } from '@obinexusltd/obix-jsx-components';
function LoginForm() {
return (
<obix-form label="Login">
<obix-input
name="email"
type="email"
label="Email"
required
/>
<obix-input
name="password"
type="password"
label="Password"
required
/>
<obix-button label="Sign In" variant="primary" />
</obix-form>
);
}
const form = LoginForm();
document.getElementById('app').innerHTML = form.render(form.state);3. Server-Side Rendering
import express from 'express';
import { h } from '@obinexusltd/obix-jsx-adapter';
import { obixCard, obixButton } from '@obinexusltd/obix-jsx-components';
const app = express();
app.get('/', (req, res) => {
const card = h(obixCard, { title: 'Dashboard' });
const button = h(obixButton, { label: 'Get Started', variant: 'primary' });
const html = `
<!DOCTYPE html>
<html>
<body>
${card.render(card.state)}
${button.render(button.state)}
</body>
</html>
`;
res.send(html);
});
app.listen(3000);Component API
Button
import { obixButton } from '@obinexusltd/obix-jsx-components';
const button = h(obixButton, {
label: 'Save', // string
variant: 'primary', // 'default' | 'primary' | 'secondary' | 'danger'
size: 'md', // 'sm' | 'md' | 'lg'
disabled: false, // boolean
loading: false, // boolean
type: 'button', // 'button' | 'submit' | 'reset'
ariaLabel: 'Save changes', // string
icon: 'save', // string
className: 'custom-class' // string
});Input
import { obixInput } from '@obinexusltd/obix-jsx-components';
const input = h(obixInput, {
name: 'email', // string
type: 'email', // 'text' | 'email' | 'password' | 'number' | ...
label: 'Email Address', // string
placeholder: '[email protected]', // string
value: '', // string
required: true, // boolean
disabled: false, // boolean
minLength: 0, // number
maxLength: 255, // number
error: null, // string | null
hint: 'We\'ll never share.', // string
validation: 'blur', // 'blur' | 'change' | 'submit'
ariaLabel: 'Email', // string
ariaDescribedBy: 'email-help' // string
});Form
import { obixForm } from '@obinexusltd/obix-jsx-components';
const form = h(obixForm, {
label: 'Contact Us', // string
legend: 'Send us a message', // string
noValidate: false, // boolean
errorSummary: true, // boolean
ariaLabel: 'Contact form' // string
});
// Add children via h()
const emailInput = h(obixInput, { label: 'Email', type: 'email' });
const messageInput = h(obixInput, { label: 'Message' });
const submitBtn = h(obixButton, { label: 'Send' });
const completeForm = h(obixForm, { label: 'Contact' }, emailInput, messageInput, submitBtn);Alert
import { obixAlert } from '@obinexusltd/obix-jsx-components';
const alert = h(obixAlert, {
message: 'Operation successful!', // string
type: 'success', // 'info' | 'success' | 'warning' | 'error'
title: 'Success', // string
dismissible: true, // boolean
ariaLive: 'polite' // 'polite' | 'assertive'
});All 30 Components
Full API reference available in COMPONENT_API.md
Paradigm Usage
Functional (Immutable)
import { toJSXFunctional } from '@obinexusltd/obix-jsx-integration';
const button = h(obixButton, { label: 'Count: 0' });
const functional = toJSXFunctional(button);
let count = 0;
function increment() {
count++;
const newState = functional.dispatch('setLabel', `Count: ${count}`);
const html = button.render(newState);
document.getElementById('app').innerHTML = html;
}OOP (Mutable)
import { toJSXOOP } from '@obinexusltd/obix-jsx-integration';
const button = h(obixButton, { label: 'Count: 0' });
const oop = toJSXOOP(button);
let count = 0;
function increment() {
count++;
oop.instance.label = `Count: ${count}`;
const html = button.render(oop.instance);
document.getElementById('app').innerHTML = html;
}Reactive (Observer)
import { toJSXReactive } from '@obinexusltd/obix-jsx-integration';
const button = h(obixButton, { label: 'Count: 0' });
const reactive = toJSXReactive(button);
let count = 0;
reactive.subscribe((newState) => {
const html = button.render(newState);
document.getElementById('app').innerHTML = html;
});
function increment() {
count++;
reactive.dispatch('setLabel', `Count: ${count}`);
}Testing
Run Tests
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage reportTest Structure
Each component has three test layers:
- Unit Test — Factory creates correct object shape
- Render Test —
.render(state)produces valid HTML - Integration Test — Works with
h()factory and paradigms
Example:
describe('obixButton', () => {
it('creates component with correct shape', () => {
const button = obixButton({ label: 'Save' });
expect(button).toHaveProperty('state');
expect(button).toHaveProperty('actions');
expect(button).toHaveProperty('render');
});
it('renders HTML string from state', () => {
const button = obixButton({ label: 'Save' });
const html = button.render(button.state);
expect(html).toContain('Save');
});
it('works with h() factory', () => {
const button = h(obixButton, { label: 'Save' });
expect(button.render(button.state)).toContain('Save');
});
});Examples
Vanilla JS + HTML/CSS
See: examples/vanilla-js/
Server-Side Rendering
See: examples/server-side/
Functional Paradigm
See: examples/functional-paradigm/
CSS Classes & Styles
All components use consistent BEM naming convention:
.obix-[component]
.obix-[component]__[element]
.obix-[component]--[modifier]Examples:
.obix-button.obix-button--primary.obix-button--disabled.obix-input-group.obix-input__label.obix-input--error.obix-form__legend
Styles are not included in this package. Import from @obinexusltd/obix-component-runtime:
import '@obinexusltd/obix-component-runtime/styles';Accessibility
All components follow WCAG 2.1 AA standards:
✅ ARIA Attributes — Roles, labels, descriptions, live regions
✅ Keyboard Navigation — Fully operable without mouse
✅ Touch Targets — Minimum 48×48 pixels
✅ Contrast — 4.5:1 minimum for text
✅ Focus Indicators — Always visible
✅ Semantic HTML — Proper fieldsets, legends, labels
Example:
const input = h(obixInput, {
label: 'Email Address', // Associated label
required: true, // aria-required
ariaDescribedBy: 'email-help', // aria-describedby
error: 'Invalid email', // aria-invalid
hint: 'We\'ll never share' // Accessible hint
});Browser Support
| Browser | Version | |---------|---------| | Chrome | 90+ | | Firefox | 88+ | | Safari | 14+ | | Edge | 90+ | | Node.js (SSR) | 18+ |
Publishing
This package is published to NPM:
npm install @obinexusltd/obix-jsx-componentsVersion History
- 0.1.0 (2026-06-03) — Initial release with 30 components, full test suite, examples
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new components
- Ensure all tests pass
- Submit a pull request
Support
- Documentation: docs.obinexus.org
- Issues: github.com/OBINexus/obix-jsx-components/issues
- Community: community.obinexus.org
License
MIT © 2026 Nnamdi Okpalan / OBINexus Computing
Related Packages
@obinexusltd/obix-jsx-adapter— JSX hyperscript factory@obinexusltd/obix-jsx-integration— DOP paradigm bridge@obinexusltd/obix-component-runtime— Core OBIX runtime@obinexusltd/obix-dop-adapter— Functional/OOP/Reactive adapters
Built with ❤️ for accessibility-first UI development
