@rufous/ui
v0.1.81
Published
Experimental: A lightweight React UI component library (Beta)
Downloads
1,398
Readme
Rufous UI
A polished React component library built with design tokens, TypeScript, and zero runtime dependencies beyond React. Every component supports the sx prop for scoped style overrides.
Live Showcase → ui.dev.rufous.com
Installation
npm install @rufous/ui
# or
yarn add @rufous/uiSetup
Import the global styles once in your app entry:
import "@rufous/ui/style.css";Wrap your app with the theme provider:
import { RufousThemeProvider } from "@rufous/ui";
import "@rufous/ui/style.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<RufousThemeProvider>
<App />
</RufousThemeProvider>
);Components
Buttons
import { StandardButton, AddButton, SubmitButton, CancelButton } from "@rufous/ui";
<StandardButton onClick={fn}>Standard</StandardButton>
<AddButton onClick={fn}>Add Item</AddButton>
<SubmitButton onClick={asyncFn}>Save</SubmitButton>
<CancelButton onClick={fn}>Cancel</CancelButton>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onClick | () => void \| Promise<void> | — | Supports async; shows loader until resolved |
| isLoading | boolean | false | External loading state control |
| disabled | boolean | false | Disables the button |
| sx | SxProp | — | Scoped style overrides |
TextField
import { TextField } from "@rufous/ui";
<TextField
label="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
variant="outlined"
required
/>| Prop | Type | Default |
|------|------|---------|
| label | string | — |
| variant | 'outlined' \| 'filled' \| 'standard' | 'outlined' |
| size | 'small' \| 'medium' | 'medium' |
| color | 'primary' \| 'secondary' \| 'error' \| 'success' \| 'warning' \| 'info' | 'primary' |
| error | boolean | false |
| helperText | ReactNode | — |
| fullWidth | boolean | false |
| InputProps | { startAdornment?, endAdornment? } | — |
| sx | SxProp | — |
Select
import { Select } from "@rufous/ui";
<Select
options={[{ value: "us", label: "United States" }]}
value={country}
onChange={setCountry}
label="Country"
/>
// Multiple selection
<Select options={options} value={selected} onChange={setSelected} multiple label="Tags" />DateField / DateRangeField
import { DateField, DateRangeField } from "@rufous/ui";
<DateField label="Start Date" value={date} onChange={setDate} />
<DateRangeField
label="Date Range"
value={range}
onChange={setRange}
/>Autocomplete
import { Autocomplete } from "@rufous/ui";
<Autocomplete
options={["React", "Vue", "Angular"]}
value={val}
onChange={setVal}
label="Framework"
/>Checkbox
import { Checkbox } from "@rufous/ui";
<Checkbox
label="I agree to the terms"
checked={checked}
onChange={setChecked}
/>Dialog
import { BaseDialog } from "@rufous/ui";
<BaseDialog
open={open}
title="Confirm Delete"
onClose={onClose}
onConfirm={onConfirm}
showCancelButton
fullWidth
>
<p>Are you sure you want to delete this item?</p>
</BaseDialog>| Prop | Type | Description |
|------|------|-------------|
| open | boolean | Controls visibility |
| title | string | Dialog title |
| onClose | () => void | Close handler |
| onConfirm | () => void \| Promise<void> | Async confirm; shows loader |
| showCancelButton | boolean | Show cancel button |
| fullWidth | boolean | Full container width |
| sx | SxProp | Scoped style overrides |
Slider
import { Slider } from "@rufous/ui";
<Slider label="Volume" value={vol} onChange={setVol} valueLabelDisplay="auto" />
// Range
<Slider label="Price" value={[20, 80]} onChange={setRange} range min={0} max={200} />Switch
import { Switch } from "@rufous/ui";
<Switch checked={on} onChange={setOn} label="Enable notifications" />RadioGroup
import { RadioGroup, Radio } from "@rufous/ui";
<RadioGroup label="Payment" options={options} value={val} onChange={setVal} />
// Composed
<RadioGroup value={val} onChange={setVal}>
<Radio value="card" label="Credit Card" />
<Radio value="paypal" label="PayPal" />
</RadioGroup>Rating
import { Rating } from "@rufous/ui";
<Rating value={stars} onChange={setStars} />
<Rating value={4.5} precision={0.5} readOnly />ToggleButton
import { ToggleButtonGroup, ToggleButton } from "@rufous/ui";
// Exclusive (radio)
<ToggleButtonGroup value={alignment} onChange={setAlignment} exclusive>
<ToggleButton value="left">Left</ToggleButton>
<ToggleButton value="center">Center</ToggleButton>
<ToggleButton value="right">Right</ToggleButton>
</ToggleButtonGroup>
// Multi-select
<ToggleButtonGroup value={formats} onChange={setFormats}>
<ToggleButton value="bold"><strong>B</strong></ToggleButton>
<ToggleButton value="italic"><em>I</em></ToggleButton>
</ToggleButtonGroup>Avatar
import { Avatar, AvatarGroup } from "@rufous/ui";
<Avatar src="/photo.jpg" alt="Alice Johnson" size="medium" />
<Avatar alt="Alice Johnson" color="#a41b06" /> // initials fallback
<AvatarGroup max={4}>
<Avatar alt="Alice" />
<Avatar alt="Bob" color="#1565c0" />
</AvatarGroup>Chip
import { Chip } from "@rufous/ui";
<Chip label="React" color="primary" />
<Chip label="Remove me" color="error" onDelete={() => {}} />
<Chip label="Click me" color="default" variant="outlined" onClick={fn} />Divider
import { Divider } from "@rufous/ui";
<Divider />
<Divider variant="middle" />
<Divider textAlign="center">OR</Divider>
<Divider orientation="vertical" flexItem />List
import { List, ListItem, ListItemText, ListItemButton, ListItemIcon, ListSubheader } from "@rufous/ui";
<List subheader={<ListSubheader>Inbox</ListSubheader>}>
<ListItemButton selected onClick={fn}>
<ListItemIcon>📩</ListItemIcon>
<ListItemText primary="Messages" secondary="3 unread" />
</ListItemButton>
</List>Typography
import { Typography } from "@rufous/ui";
<Typography variant="h1">Heading</Typography>
<Typography variant="body1" color="textSecondary">Paragraph text</Typography>
<Typography variant="caption" gutterBottom>Caption</Typography>Skeleton
import { Skeleton } from "@rufous/ui";
<Skeleton variant="text" width={200} />
<Skeleton variant="circular" width={40} height={40} />
<Skeleton variant="rounded" width={300} height={120} animation="wave" />Tooltip
import { Tooltip } from "@rufous/ui";
<Tooltip title="Delete this item" placement="top" arrow>
<button>Delete</button>
</Tooltip>Progress
import { CircularProgress, RufousLogoLoader } from "@rufous/ui";
<CircularProgress size={36} />
<RufousLogoLoader />Box / Stack / Grid
import { Box, Stack, Grid } from "@rufous/ui";
// Box — generic flex/layout container
<Box display="flex" gap={16} padding={24}>...</Box>
// Stack — 1D flex layout
<Stack direction="row" spacing={2}>
<div>A</div>
<div>B</div>
</Stack>
// Grid — 12-column responsive grid
<Grid container spacing={3}>
<Grid item xs={12} md={6}>Main</Grid>
<Grid item xs={12} md={6}>Sidebar</Grid>
</Grid>Paper / Card / Accordion
import { Paper, Card, CardContent, CardHeader, CardActions, Accordion, AccordionSummary, AccordionDetails } from "@rufous/ui";
<Paper elevation={3}>Content</Paper>
<Card>
<CardHeader title="Title" subheader="Subtitle" />
<CardContent>Body</CardContent>
<CardActions><button>Action</button></CardActions>
</Card>
<Accordion>
<AccordionSummary>FAQ Question</AccordionSummary>
<AccordionDetails>Answer text here.</AccordionDetails>
</Accordion>Tabs
import { Tabs, Tab } from "@rufous/ui";
<Tabs value={tab} onChange={setTab}>
<Tab value="home" label="Home" />
<Tab value="settings" label="Settings" />
</Tabs>Breadcrumbs
import { Breadcrumbs } from "@rufous/ui";
<Breadcrumbs separator="›">
<a href="/">Home</a>
<a href="/products">Products</a>
<span>Current</span>
</Breadcrumbs>Stepper
import { Stepper, Step, StepLabel, StepContent } from "@rufous/ui";
<Stepper activeStep={activeStep}>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>Menu
import { Menu, MenuItem, MenuList, MenuDivider } from "@rufous/ui";
<Menu open={open} anchorEl={anchorRef.current} onClose={() => setOpen(false)}>
<MenuList>
<MenuItem icon="👤">Profile</MenuItem>
<MenuItem icon="⚙️">Settings</MenuItem>
<MenuDivider />
<MenuItem icon="🚪">Sign Out</MenuItem>
</MenuList>
</Menu>Drawer
import { Drawer } from "@rufous/ui";
<Drawer open={open} onClose={() => setOpen(false)} anchor="right" width={320}>
<div style={{ padding: 24 }}>Drawer content</div>
</Drawer>Snackbar
import { Snackbar } from "@rufous/ui";
<Snackbar
open={open}
onClose={() => setOpen(false)}
message="Changes saved successfully"
severity="success"
autoHideDuration={4000}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
/>Link
import { Link } from "@rufous/ui";
<Link href="/docs" color="primary">Documentation</Link>
<Link component="button" color="primary" onClick={fn}>Trigger action</Link>Popper / Popover
import { Popper, Popover } from "@rufous/ui";
// Popper — no backdrop, low-level
<Popper open={open} anchorEl={anchorRef.current} placement="bottom-start">
<div>Custom dropdown content</div>
</Popper>
// Popover — backdrop, closes on outside click
<Popover open={open} anchorEl={anchorRef.current} onClose={() => setOpen(false)}>
<div style={{ padding: 20 }}>Popover content</div>
</Popover>Transitions
import { Fade, Slide, Grow, Collapse, Zoom } from "@rufous/ui";
<Fade in={show}><div>Fades in/out</div></Fade>
<Slide in={show} direction="up"><div>Slides in from bottom</div></Slide>
<Grow in={show}><div>Grows from center</div></Grow>
<Collapse in={show}><div>Collapses vertically</div></Collapse>
<Zoom in={show}><div>Zooms in/out</div></Zoom>Icons
import { CopyIcon, EditIcon, TrashIcon, DownloadIcon } from "@rufous/ui";
<CopyIcon onClick={() => copy(text)} />
<EditIcon />
<TrashIcon />
<DownloadIcon />The sx Prop
Every component accepts an sx prop for scoped, per-instance style overrides using nested CSS selectors. Values are injected as a scoped <style> tag — no inline style conflicts.
import { TextField } from "@rufous/ui";
import type { SxProp } from "@rufous/ui";
<TextField
label="Search"
sx={{
borderRadius: "12px",
"& .rf-text-field__input": { fontSize: "0.9rem" },
"&:hover": { boxShadow: "0 0 0 3px rgba(164,27,6,0.15)" },
}}
/>License
MIT © Rufous UI
