A set of documented, typed and tested libraries that work great together. Each one does one thing and does it well. Perfect for small or mid-size projects.
// react-test — readable assertions, zero boilerplate
import $ from 'react-test';
import Counter from './Counter';
it('renders with initial value', async () => {
const counter = $(<Counter />);
expect(counter.text()).toBe('0');
});
it('increments on click', async () => {
const counter = $(<Counter />);
await counter.find('button').click();
expect(counter.text()).toBe('1');
await counter.find('button').click();
expect(counter.text()).toBe('2');
});
// form-mate — tiny, elegant form handling
import Form from 'form-mate';
function SignupForm() {
const onSubmit = async ({ name, email }) => {
await api.post('/users', { name, email });
};
return (
<Form onSubmit={onSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" required />
<button>Sign up</button>
</Form>
);
}
// statux — immutable state with React Hooks
import Store, { useStore } from 'statux';
function CartButton() {
const [cart, setCart] = useStore('cart');
const onAdd = () => setCart.append('Apple');
return (
<button onClick={onAdd}>
Cart ({cart.length})
</button>
);
}
function App() {
return <Store cart={[]}><CartButton /></Store>;
}
// crossroad — simple, hook-based routing
import Router, { Route, Switch } from 'crossroad';
function App() {
return (
<Router>
<a href="/">Home</a>
<a href="/about">About</a>
<Switch>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/users/:id" component={Profile} />
</Switch>
</Router>
);
}
Readable assertions for React. Ship with confidence, fewer bugs.
Navigation with simple components and hooks. Write cleaner code.
Immutable global state with React Hooks. No ceremony required.
Tiny and elegant form handling. No boilerplate, just clean forms.
Localization for React and React Native. Stays out of your way.
Async operations made easy. Loading, errors, data — minimal code.
Easier API calls. Like Axios, but a fraction of the size.
Real CSS in JavaScript. Visual primitives for the component age.
Make readable assertions for your React components. Write tests that feel natural, catch bugs before they reach users, and keep your test suite easy to maintain.
npm install react-test
Testing Library requires juggling multiple query strategies and async utilities. react-test gives you a single, chainable API that just works.
import $ from 'react-test';
import Form from './Form';
it('submits the form', async () => {
const onSubmit = jest.fn();
const form = $(<Form onSubmit={onSubmit} />);
await form.find('[name="email"]').type('[email protected]');
await form.find('button').click();
expect(onSubmit).toHaveBeenCalledWith(
{ email: '[email protected]' }
);
});
Handle navigation in your React app with simple components and hooks. No configuration objects, no context providers to remember — just routes.
npm install crossroad
import Router, { Route, Switch } from 'crossroad';
function App() {
return (
<Router>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<Switch>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</Router>
);
}
Global state management built on React Hooks with immutable state. Wrap your app in a Store, read and update from anywhere — no actions, no reducers.
npm install statux
Statux works similar to useState(), but with a global state. No need to train everyone (including your LLM) about action creators, reducers, selectors, middleware, etc.
import Store, { useStore } from 'statux';
function App() {
return (
<Store user={null} cart={[]}>
<Page />
</Store>
);
}
function Header() {
const [user] = useStore('user');
return <h1>Hello, {user?.name ?? 'guest'}</h1>;
}
Tiny form handling with zero boilerplate. Wrap your inputs in a Form, get typed data in onSubmit — no registration, no schema, no ref juggling.
npm install form-mate
react-hook-form needs field registration and refs. form-mate reads values directly from the DOM using name attributes.
import Form from 'form-mate';
function SignupForm() {
const onSubmit = ({ name, email }) =>
register({ name, email });
return (
<Form onSubmit={onSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" required />
<input name="password" type="password" required />
<button>Sign up</button>
</Form>
);
}
Localization for React and React Native. Define your translations as plain objects and render them with a simple component — no JSON files, no key lookups.
npm install react-text
react-i18next needs providers, files, and hooks. react-text keeps everything in your components with minimal setup.
import Text from 'react-text';
const dictionary = {
hello: { en: 'Hello, World!', es: '¡Hola, Mundo!' },
bye: { en: 'Goodbye!', es: '¡Adiós!' },
};
function App() {
return (
<Text language="es" dictionary={dictionary}>
<p><Text hello /></p>
<p><Text bye /></p>
</Text>
);
}
Async data fetching with automatic cancellation. Returns
{ data, error, loading }, re-runs when dependencies
change, and aborts stale requests automatically.
npm install use-async
react-query adds caching, clients, and config. useAsync focuses on the basics: run async code and return the result.
import useAsync from 'use-async';
const getUser = async (signal, id) =>
api.get(`/users/${id}`, { signal });
function UserProfile({ id }) {
const { data, error, loading } = useAsync(getUser, [id]);
if (loading) return <Spinner />;
if (error) return <ErrorPage />;
return <Profile user={data} />;
}
A tiny fetch wrapper that removes the boilerplate from API calls. Automatic JSON parsing, method shortcuts, and base URL support — no instance required.
npm install fch
axios wraps responses and needs setup. fch returns the data directly with a much smaller footprint.
import fch from 'fch';
// GET — returns parsed JSON directly
const users = await fch('/api/users');
// POST with body
const user = await fch.post('/api/users', { name: 'Alice' });
// Create instance with base URL
const api = fch.create({ baseUrl: 'https://api.example.com' });
const data = await api.get('/users');
Write real CSS scoped to your components, with full access to props and theming. No class name collisions, no separate stylesheet to maintain.
npm install styled-components
CSS Modules require separate files and class names. styled-components keeps styles next to your components with full JS access.
import styled from 'styled-components';
const Card = styled.div`
background: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
`;
const Title = styled.h2`
font-size: 20px;
color: ${p => p.muted ? '#888' : '#111'};
`;