simple-blog-ui
v0.4.2
Published
Terminal-style UI component library for simple-blog. 45 Web Components that work in plain HTML, React, and Vue. Built with Lit. Monospace, uppercase, 2px solid borders, zero rounded corners.
Downloads
1,025
Maintainers
Readme
simple-blog-ui
The UI kit for your terminal-style blog.
A framework-agnostic component library built with Lit — drop it into plain HTML, React, or Vue and get 45 Web Components styled after mkdocs-simple-blog: Fira Mono, uppercase, 2px borders, zero rounded corners. The kind of UI that looks like it was typeset on a Selectric.
📖 Live Storybook: fernandocelmer.github.io/simple-blog-ui
Why?
- One lib, three stacks. Web Components are native — write them once, use them everywhere.
- Opinionated design, zero configuration. The whole kit follows a single aesthetic: monospace terminal chic. No theme configuration required to look good.
- Dark mode baked in. Flip
data-theme="dark"on<html>and every component inverts correctly. - Syntax highlighting included.
<sb-code>auto-highlights JavaScript, Python, Bash, JSON, HTML and 30+ more languages via highlight.js. - Tiny. ~5KB Lit runtime + per-component shadow DOM. No global CSS-in-JS bloat.
- React-first DX. Official PascalCase wrappers via
simple-blog-ui/reactturn custom events (sb-click,sb-change) into native React handlers (onClick,onChange). - Blog-ready. Includes a dedicated Blog category with layout, sidebar, footer and prev/next primitives — drop-in building blocks for a documentation site.
Install
npm install simple-blog-uiQuick start
HTML
<script type="module">
import 'simple-blog-ui';
</script>
<link rel="stylesheet" href="node_modules/simple-blog-ui/src/styles/main.css" />
<sb-button variant="primary">Click me</sb-button>React
import { Button, Input, Alert } from 'simple-blog-ui/react';
import 'simple-blog-ui/style.css';
export default function App() {
return (
<>
<Button variant="primary" onClick={() => alert('hi')}>Click me</Button>
<Input label="Email" onInput={(e) => console.log(e.detail.value)} />
<Alert variant="success" title="Saved">Done.</Alert>
</>
);
}Vue 3
<script setup>
import 'simple-blog-ui';
import 'simple-blog-ui/style.css';
</script>
<template>
<sb-button variant="primary" @sb-click="onClick">Click me</sb-button>
</template>Tell Vue that sb-* is a custom element — add to your vite.config:
vue({ template: { compilerOptions: { isCustomElement: (t) => t.startsWith('sb-') } } })Components
45 components · 9 categories · all in the same minimalist style.
| Category | Count | Components |
| -------------- | :---: | ----------------------------------------------------------------------------------------------- |
| actions | 4 | sb-button · sb-icon-button · sb-button-group · sb-close-button |
| typography | 3 | sb-heading · sb-text · sb-code |
| layout | 3 | sb-container · sb-stack · sb-divider |
| display | 9 | sb-card · sb-avatar · sb-badge · sb-tag · sb-accordion · sb-collapse · sb-list-group · sb-carousel · sb-table |
| forms | 4 | sb-input · sb-textarea · sb-checkbox · sb-switch |
| feedback | 4 | sb-alert · sb-spinner · sb-progress · sb-toast |
| navigation | 6 | sb-link · sb-tabs · sb-nav · sb-navbar · sb-breadcrumb · sb-pagination |
| overlays | 5 | sb-modal · sb-tooltip · sb-dropdown · sb-offcanvas · sb-popover |
| blog 🆕 | 7 | sb-page-layout · sb-sidebar · sb-footer · sb-prev-next · sb-post-list · sb-profile · sb-error-page |
Play with every single one in the Storybook.
Blog primitives
The blog category provides the building blocks for a documentation-style site (used in production by mkdocs-simple-blog):
| Component | What it does |
|---|---|
| <sb-page-layout> | Max-width container + 25/75 sidebar/content grid. Collapses to one column on mobile. |
| <sb-sidebar> | Nested TOC — pass items as JSON (supports unlimited depth). |
| <sb-footer> | Centered footer section with top border and stacked items. |
| <sb-prev-next> | 3-column prev/next post navigation. |
| <sb-post-list> | Post index with date + title columns. |
| <sb-profile> | Centered about page — name, role, bio slot, social links. |
| <sb-error-page> | 404/500 with oversized code + message and action slot. |
React — event handling
Custom events map to standard React props. The CustomEvent payload lives at event.detail.
| React prop | Components |
| --------------- | --------------------------------------- |
| onClick | Button · IconButton |
| onChange | Input · Checkbox · Switch · Accordion |
| onInput | Input · Textarea |
| onClose | Modal · Offcanvas · Toast · CloseButton |
| onSelect | Dropdown · ListGroup |
| onPageChange | Pagination |
| onTabChange | Tabs |
| onDismiss | Alert |
| onRemove | Tag |
| onToggle | Collapse |
| onSlide | Carousel |
Theming
Two themes out of the box. Toggle with a single attribute:
<html data-theme="dark">Every component reads its colors and spacing from CSS custom properties defined in root.css. Override any of them to re-theme globally:
:root {
--primary: #1e40af; /* change primary accent */
--color-red: #b91c1c; /* change error color */
--background: #fef3c7; /* change page background */
}Core tokens (inherited verbatim from mkdocs-simple-blog):
--text: #000 --color-blue: #4051b5
--title: #000 --color-green: #4cae4f
--primary: #000 --color-yellow: #f1dc15
--background: #fff --color-orange: #ffa724
--color-gray: #808080
--color-purple: #ab47bd
--color-red: #ff2c06Storybook and docs
Every component has a live Storybook page with HTML / React / Vue code tabs, interactive controls, and the full set of variants.
npm install
npm run storybook # opens http://localhost:6006Three usage guides inside Storybook: Usage / HTML, Usage / React, Usage / Vue — plus Design / Colors and Design / Typography for the full token map.
Scripts
npm run storybook # dev server at :6006
npm run build # library build (ESM + CJS)
npm run build-storybook # static Storybook site
npm pack # produce a local tarball for testingWhy Web Components (and Lit)?
The lib is built with Lit, which compiles to standard Web Components — native browser APIs. That means:
- No framework lock-in. A
<sb-button>is just an HTML element with Shadow DOM. It works in React, Vue, Svelte, Solid, Angular, plain HTML, or any future framework. - Scoped styles. Shadow DOM isolates each component's CSS — no class name collisions, no global leaks.
- Tiny runtime. Lit is ~5KB gzip, loaded once for the whole library. No per-component bundle bloat.
- Future-proof. Web Components are a W3C standard. Your investment survives framework churn.
How it compares
| Library | Distribution | Design system | Dark mode | Frameworks | Blog primitives | |---|---|---|---|---|---| | simple-blog-ui | npm (ESM + CJS) | Monospace, B&W, 2px borders | ✅ built-in | HTML · React · Vue | ✅ Page layout · TOC · Prev/Next | | Shoelace | npm | Modern, rounded | ✅ | all via WC | ❌ | | MUI | npm | Material Design | ✅ | React only | ❌ | | Chakra UI | npm | Clean, rounded | ✅ | React only | ❌ | | shadcn/ui | copy-paste | Opinionated | ✅ | React only | ❌ |
When to pick simple-blog-ui — you want a clean, opinionated monospace/terminal aesthetic, your app or blog is documentation-centric, or you want one lib that works across React and Vue without rewrites.
FAQ
Does it work with Next.js / Nuxt? Yes. Register the components client-side (Next: in a client component; Nuxt: via a .client.ts plugin). Both frameworks support Web Components.
What about SSR? Components render in the browser (Shadow DOM is client-side). The server sends the <sb-*> tags, the client hydrates. For pre-rendered HTML you can use Lit SSR separately — not included here.
Is it tree-shakeable? Individual components can be imported per-file in the React wrapper layer (import { Button } from 'simple-blog-ui/react'). The Web Component registrations in the main entry are side-effect imports — the full set is ~96KB gzipped.
Can I theme it? Yes. All colors, fonts, spacing come from CSS custom properties. Override on :root to re-theme globally or on any parent for scoped overrides.
Is there a Figma kit? Not yet.
How do I contribute? Open an issue or PR at github.com/FernandoCelmer/simple-blog-ui.
Credits
Born as a React/Vue companion to mkdocs-simple-blog. Built with Lit and highlight.js. React wrappers generated via @lit/react. Documented with Storybook.
License
MIT — Fernando Celmer
