Bootstrap 5.3.8 UI, rebuilt in
styled-components. CSS-in-JS, React 18, TypeScript, and a
runtime --bs-* token surface — the modern rewrite of
bootstrap-styled/v4. Every component, helper, and utility
is rendered pixel-for-pixel against a vendored Bootstrap 5.3.8 oracle by a hermetic parity harness.
📖 Documentation & live component demos → bootstrap-styled.metatoy.com
Status — v1.0.0, published. Full Bootstrap 5.3.8 parity, live on npm as
@metatoy/bootstrap-styled@1.0.0. CI (typecheck · test · build · the parity visual-regression gate) and the docs build run green onmain. SeeCHANGELOG.mdandparity/scorecard.mdfor the specifics.
- Quickstart
- Components
- Utilities —
<Box>and<Icon> - Dark mode
- Parity harness
- Documentation
- License MIT
npm i @metatoy/bootstrap-styled styled-components react react-dom| Package | Version |
|---|---|
react |
≥ 18 |
react-dom |
≥ 18 |
styled-components |
≥ 6 |
@floating-ui/react |
≥ 0.26 (auto-installed) |
bootstrap-icons |
(bundled — powers <Icon/>) |
Wrap your app in BootstrapStyledProvider — it injects the theme as --bs-* CSS variables and
provides the styled-components theme context. (The package exports it as BootstrapStyledProvider.)
import { BootstrapStyledProvider, Button } from '@metatoy/bootstrap-styled'
export default function App() {
return (
<BootstrapStyledProvider>
<Button variant="primary">Hello!</Button>
</BootstrapStyledProvider>
)
}createTheme() deep-merges overrides onto Bootstrap 5 defaults. The provider projects the theme onto
--bs-* CSS variables at runtime — changing the theme re-skins every component instantly, no
re-bundling needed.
import { BootstrapStyledProvider, createTheme, Button } from '@metatoy/bootstrap-styled'
const theme = createTheme({ colors: { primary: '#7c3aed' } })
export function App() {
return (
<BootstrapStyledProvider theme={theme} colorMode="light">
<Button variant="primary">Save</Button>
<Button variant="outline-danger">Delete</Button>
</BootstrapStyledProvider>
)
}The full Bootstrap 5.3.8 roster, all exported from the package root:
- Actions & indicators —
Button,ButtonGroup,Badge,Spinner,Progress,Placeholder,CloseButton,Toast. - Content & layout —
Container/Row/Colgrid,Stack,Ratio,Typography,Table,Image,Figure,Card,ListGroup,Carousel. - Navigation —
Nav,Navbar,Tabs,Breadcrumb,Pagination,Scrollspy,Collapse,Accordion. - Feedback & overlays (on
@floating-ui/react) —Alert,Modal,Offcanvas,Dropdown,Tooltip,Popover. - Forms —
FormControl(incl.as="textarea", sizes,isInvalid/isValid),FormSelect,FormCheck(checkbox/radio/switch),FormRange,FloatingLabel,FormFeedback,FormLabel,FormText,FormGroup,InputGroup/InputGroupText. - Helpers —
Clearfix,TextBg,FocusRing,IconLink, Position (FixedTop/FixedBottom/StickyTop/StickyBottom/TranslateMiddle),StretchedLink,TextTruncate,Vr,VisuallyHidden.
A polymorphic layout primitive (as, default div) that carries Bootstrap's utility system as typed
props. Each value maps 1:1 to the exact Bootstrap utility class, and responsive object syntax
expands to breakpoint classes.
import { Box } from '@metatoy/bootstrap-styled'
<Box m={3} d="flex" bg="primary" /> // → <div class="m-3 d-flex bg-primary" />
<Box m={{ base: 2, md: 4 }} p={3} /> // → <div class="m-2 m-md-4 p-3" />
<Box as="section" rounded bg="body-tertiary" />
Boxemits utility classes; those classes render correctly when Bootstrap's utility CSS is present (shipped via your global stylesheet / theme surface).
import { Icon } from '@metatoy/bootstrap-styled'
<Icon name="alarm" />
<Icon name="chevron-down" width={20} /><Icon name="…" /> resolves from a bundled registry and renders the SVG inline. For zero bundle tax,
prefer the tree-shakeable per-icon exports so only the icons you use are included. Run
npm run gen:icons to regenerate the full registry from bootstrap-icons.
Dark mode uses Bootstrap's native data-bs-theme attribute — no separate stylesheet. Set it on the
provider and read/toggle it via useColorMode.
import { BootstrapStyledProvider, useColorMode } from '@metatoy/bootstrap-styled'
<BootstrapStyledProvider colorMode="dark">
{/* every --bs-* token flips to its dark value */}
</BootstrapStyledProvider>npm run parity runs a hermetic visual-regression + accessibility gate. It renders every
component/state cell twice — once as the styled component, once against a vendored, pinned
Bootstrap 5.3.8 oracle (no network) — captures both via Playwright/Chromium, then:
- diffs with pixelmatch (1280×1800 @2× DPR, animations frozen, threshold 0.1, AA excluded, padded to a common canvas), and
- runs axe-core on each subtree for WCAG 2.0/2.1 A/AA violations.
Results land in parity/scorecard.md / scorecard.json with per-component and per-cell diff
percentages (🟢 ≤0.5% · 🟡 ≤3% · 🔴 >3%). The eight example pages (Headers, Heroes, Features,
Jumbotron, Navbars, Sidebars, Footers, KitchenSink) are diffed the same way as the human
proof.
Interactive component demos, theming guides, and the example pages live in the
Ladle story surface (npm run docs, built with npm run docs:build →
docs-build/). Published docs: v5 documentation.
MIT. Derived in part from bootstrap-styled/v4 (© 2017–18 Yeutech, MIT) — see NOTICE.
