velosui
v2.1.1
Published
A lightweight, themeable, responsive React component library styled with Tailwind CSS.
Maintainers
Readme
VelosUI — React Component Library
VelosUI is a lightweight, themeable, and responsive React component library. Components are styled with Tailwind CSS v4 and ship as a prebuilt stylesheet, so you do not need Tailwind in your own project to use them.
Features
- Themeable — every color and radius is a CSS variable; override a token in your own CSS to re-skin everything.
- Responsive — components use responsive and orientation-aware styles and stretch to their container instead of fixed pixel widths.
- Accessible — real form controls, full keyboard support,
focus-visiblerings, and wired-uparia-*attributes. - Smart positioning —
Tooltip,Popover,Dropdown,Combobox, andMultiSelectuse Floating UI to flip and shift near viewport edges, and render in a portal so they never clip inside scroll containers. - Composable — every component forwards refs, extends its native HTML element's props, and accepts a
classNamethat wins over the defaults. - Lightweight — ESM + CJS builds, tree-shakeable, with
react/react-domas peer dependencies.
Installation
npm install velosui
# or: pnpm add velosuiThen import the stylesheet once at your app's entry point:
import 'velosui/styles.css'Usage
import { Button, Input, Checkbox } from 'velosui'
function Example() {
return (
<form>
<Input label="Email" type="email" placeholder="[email protected]" />
<Checkbox label="Remember me" />
<Button variant="primary" fullWidth>
Sign in
</Button>
</form>
)
}Theming
Tokens are defined as CSS variables. Override them in your own stylesheet (loaded after velosui/styles.css):
:root {
--color-primary: #16a34a;
--color-primary-hover: #15803d;
--radius-control: 0.75rem;
}You can also override styles per instance with className — VelosUI merges classes so yours take precedence:
<Button className="rounded-full px-10">Pill</Button>Components
| Component | Notable props |
| ------------ | ------------- |
| Button | variant (primary | secondary | danger), size, loading, fullWidth + all <button> props |
| Input | label, size, value/defaultValue, onChange(value), validate, error + all <input> props |
| Textarea | label, resize, rows, onChange(value), validate, error + all <textarea> props |
| Select | label, size, options, placeholder, onChange(value), error + all <select> props |
| Checkbox | label, variant (rounded | squared), indeterminate, checked/defaultChecked, onChange(checked) |
| Switch | label, size, checked/defaultChecked, onChange(checked) |
| RadioGroup | label, value/defaultValue, onChange(value), orientation; wraps <Radio value label /> items |
| Badge | variant (neutral | primary | success | warning | danger), size |
| Spinner | size, label (inherits currentColor) |
| Card | container + CardHeader / CardTitle / CardDescription / CardContent / CardFooter; flush to drop padding |
| Tooltip | content, placement (top | bottom | left | right), openDelay; wraps a single trigger element |
| Tabs | value/defaultValue, onChange(value), orientation; composed of TabList / Tab / TabPanel (arrow-key navigable) |
| Modal | open, onClose, title, description, footer, size, closeOnOverlayClick, closeOnEsc; renders via portal with focus trap + scroll lock |
| Alert | variant (info | success | warning | danger), title, icon, onClose (dismissible) |
| Avatar | src, name (initials fallback), size, shape; AvatarGroup with max → +N overflow |
| Accordion | type (single | multiple), value/defaultValue, onChange, collapsible; composed of AccordionItem / AccordionTrigger / AccordionContent |
| Dropdown | trigger, align; menu of DropdownItem (onSelect, destructive) / DropdownSeparator / DropdownLabel; click-outside + Escape + arrow-key nav |
| Progress | value/max, size, variant, indeterminate, label, showValue; role="progressbar" |
| Skeleton | variant (text | circular | rectangular | rounded), animation (pulse | wave | none), width, height; animated placeholder |
| Breadcrumb | separator; composed of BreadcrumbItem (href, current) inside a labelled <nav> |
| Pagination | page, count, onChange, siblingCount, boundaryCount; ellipsis range via exported getPaginationRange |
| ToastProvider / useToast | Wrap the app in ToastProvider (position, duration); call const { toast } = useToast() then toast({ title, description, variant, duration }). Renders via portal, auto-dismisses. |
| Table | striped, hoverable, dense; composed of TableHeader / TableBody / TableRow / TableHead / TableCell / TableCaption |
| Slider | min/max/step, value/defaultValue, onChange(number), label, showValue; styled native range with filled track |
| Popover | trigger, side, align, controlled open/onOpenChange; click-outside + Escape, holds arbitrary content |
| Combobox | options, value/defaultValue, onChange(value), placeholder, emptyMessage; searchable with type-to-filter + keyboard nav + ARIA listbox |
| Calendar | value/defaultValue, onChange(Date), min/max; month grid with full keyboard navigation (role="grid") |
| DatePicker | value/defaultValue, onChange(Date), label, min/max, format; Calendar inside a smart-positioned Popover |
| NumberInput| value/defaultValue, onChange(number), min/max/step; stepper buttons, clamping, role="spinbutton" |
| Rating | value/defaultValue, onChange(number), max, size, readOnly; star rating with hover preview + keyboard |
| SegmentedControl | options, value/defaultValue, onChange(value), size, fullWidth; radiogroup toggle with arrow-key nav |
| Paper | variant (elevation | outlined), elevation (0–6), rounded, square; surface primitive |
| Divider | orientation (horizontal | vertical), align; optional inline label via children |
| Backdrop | open, onClose, invisible; portal scrim that fades in/out, click-to-close |
| Fab | color, size, extended + extendedLabel; floating action button (position via className) |
| SpeedDial | ariaLabel, actions, direction (up | down | left | right), icon/openIcon; a Fab that fans out actions |
| CircularProgress | size, thickness, value (determinate) + showLabel; omit value for an indeterminate ring |
| ScrollArea | axis (vertical | horizontal | both), maxHeight; slim themed scrollbars |
| Drawer | open, onClose, side (left | right | top | bottom), size, title, footer; edge panel with focus trap + scroll lock |
| Transition | in, variant (fade | grow | zoom | slide | collapse), timeout, unmountOnExit; convenience exports Fade / Grow / Zoom / Slide / Collapse |
| DataGrid | columns, rows, rowKey, selectable (select-all + indeterminate), pageSize, sortable columns; controlled/uncontrolled sort + selection |
| MultiSelect| options, value/defaultValue, onChange(values), creatable, maxItems; chips-in-field with filterable dropdown (Backspace to remove) |
| TreeView | data, expanded/selected (controlled or default), onExpandedChange/onSelect; collapsible tree with full keyboard nav |
| Carousel | slide children, loop, autoPlay + interval, showArrows, showDots, controlled index; pauses autoplay on hover |
| Dialog | open, onClose, variant (alert | confirm), tone (info | success | warning | danger), onConfirm, loading; built on Modal |
| BarChart / LineChart / Sparkline | token-driven SVG/CSS charts: data, height, showValues/showDots/area; color via currentColor |
Form components are controlled or uncontrolled, and every component forwards refs to the underlying DOM element.
Development
pnpm install
pnpm storybook # explore components at localhost:6006
pnpm test # Vitest (jsdom + Testing Library)
pnpm typecheck # tsc --noEmit (strict)
pnpm build # bundle JS (tsup) + CSS (Tailwind CLI) into dist/Components are styled with Tailwind v4 utility classes composed through a cn() helper (clsx + tailwind-merge); design tokens live in src/styles.css under @theme.
