Vanilla docs for a vanilla UI library

Scybud UI documentation

Everything in these docs is built without frameworks, bundlers, or markdown parsers. It is kept lightweight, responsive, and dark-mode-first.

Introduction

Scybud UI is a small, framework-free component and token system built to stop rewriting the same buttons, modals, and layout patterns across every Scybud product.

It ships as plain CSS and vanilla JS modules, loaded straight from a CDN with no build step. Every component on this site is the exact code running in production across LogHue, PropDek, CanvArt, and the rest of the Scybud studio.

Quickstart / Getting Started

Use the CDN and a minimal HTML setup to get Scybud UI running. This includes every core stylesheet, not just buttons, so a fresh page has layout, typography, animations, and components available immediately.

<!--SCYBUD UI CORE-->
<link rel="stylesheet" href="https://ui.scybud.com/css/variables.css" />
<link rel="stylesheet" href="https://ui.scybud.com/css/typography.css" />
<link rel="stylesheet" href="https://ui.scybud.com/css/layout.css" />
<link rel="stylesheet" href="https://ui.scybud.com/css/animations.css" />

<!--COMPONENTS-->
<link rel="stylesheet" href="https://ui.scybud.com/components/sidebar/sidebar.css" />
<link rel="stylesheet" href="https://ui.scybud.com/components/buttons/global-buttons.css" />
<link rel="stylesheet" href="https://ui.scybud.com/components/buttons/nav-buttons.css" />
<link rel="stylesheet" href="https://ui.scybud.com/components/buttons/modals.css" />
<link rel="stylesheet" href="https://ui.scybud.com/components/forms/empty-state.css" />

<!--JS (all components exported from one entry file)-->
<script type="module" src="https://ui.scybud.com/js/ui.js"></script>
<script type="module">
  import { setButtonLoading } from "https://ui.scybud.com/js/ui.js";

  const button = document.querySelector('.btn-primary');
  button.addEventListener('click', () => {
    setButtonLoading(button, true);
  });
</script>

Design Tokens

The core CSS custom properties used across Scybud UI, defined in variables.css.

Colors

  • --primary: #007fc3
  • --primary-light: #38b6ff
  • --secondary: #475569
  • --secondary-light: #94a3b8
  • --bg-primary: #000
  • --bg-secondary: #151821
  • --surface-primary: #1a1a1a
  • --surface-secondary: #151515
  • --text-primary: #f5f7fa
  • --text-secondary: #d1d5db
  • --muted: #9b9b9b
  • --border-primary: #2c2f36
  • --border-secondary: #3a3d45
  • --link: #0393d6
  • --hover-bg: #201f1f
  • --active: #393838

Spacing

  • --space-xs: 4px
  • --space-sm: 8px
  • --space-md: 16px
  • --space-lg: 24px
  • --space-xl: 32px

Typography

  • --font-primary: 'Inter', sans-serif
  • --font-mono: 'JetBrains Mono', monospace
  • --text-xs: 0.75rem
  • --text-sm: 0.875rem
  • --text-md: 1rem
  • --text-lg: 1.25rem
  • --text-xl: 1.5rem
  • --text-2xl: 1.375rem
  • --text-3xl: 1.625rem
  • --text-4xl: 1.875rem
  • weights: --font-light 300, --font-normal 400, --font-medium 500, --font-semibold 600, --font-bold 700

States, radius & motion

  • --success: #10b981
  • --warning: #f59e0b
  • --danger: #e56458
  • --radius-sm: 8px
  • --radius-md: 12px
  • --radius-lg: 28px
  • --transition-fast: 0.15s ease
  • --transition-normal: 0.25s ease
  • --transition-slow: 0.4s ease
  • --shadow: 0 4px 20px rgba(0,0,0,0.08)
  • --z-dropdown: 100, --z-modal: 500, --z-toast: 1000

Layout

The sidebar and main-content structure that every Scybud product page is built on, with a mobile drawer below 800px.

.sidebar is fixed at 260px wide on desktop. .main-content gets a matching 260px left margin. Below 800px, the sidebar slides off-screen and is toggled open with .toggle-sidebar, which adds the .open class to .sidebar and toggles .sidebar-open on <body>. A .sidebar-overlay dims the page behind the drawer and closes it on tap.

<div class="toggle-sidebar" id="globalToggleBtn">...</div>
<div class="sidebar-overlay" id="globalOverlay"></div>
<aside class="sidebar" id="globalSidebar">
  <nav class="sidebarNav">...</nav>
</aside>
<main class="main-content">...</main>

Typography

Global heading scale, paragraph styling, and text utilities.

Headings h1 through h6 map to --text-4xl down to --text-md, all bold and tight line-height. Paragraphs use --text-secondary at line-height 1.4. Links use --link with a fade on hover.

  • .text-muted — sets color to --muted
  • .text-center — center-aligns text
  • .text-bold — sets --font-bold

Component template

The reusable pattern every component doc below follows: live preview, copyable HTML, JS API, accessibility notes.

Live Preview

Copy HTML

<button class="btn btn-primary" type="button">Preview button</button>

JavaScript API

Initialization
const button = document.querySelector('.btn-primary');
Methods
  • button.focus()
  • button.click()
Events
  • click
  • keydown for keyboard interaction

Accessibility checklist

  • Use semantic native elements like <button>.
  • Provide accessible labels and focus styles.
  • Ensure contrast is maintained with dark backgrounds.
  • Keep interactions keyboard-friendly.

Buttons

Primary, secondary, pill, and no-background variants, plus a built-in loading state.

For the loading button to work, you have to import animation.css into the HTML page.

Live preview

Copy HTML

<button class="btn btn-primary" type="button">Primary</button>
<button class="btn btn-secondary" type="button">Secondary</button>
<button class="btn btn-primary btn-pill" type="button">Pill</button>
<button class="btn btn-no-bg" type="button">No background</button>

JavaScript API

  • setButtonLoading(button, isLoading) — toggles the .loading spinner state, disables the button, and sets aria-busy
  • handleBackBtn() — wires every .backBtn element on the page to window.history.back()
import { setButtonLoading, handleBackBtn } from 'https://ui.scybud.com/js/ui.js';

setButtonLoading(myButton, true);
handleBackBtn();

Accessibility

  • Use native <button> semantics.
  • Loading state sets aria-busy="true" automatically.
  • Confirm focus ring visibility and consistent contrast ratios.

Empty State

Programmatically builds a placeholder block for empty lists, inboxes, or feeds.

Live preview

Usage

<div id="feedContainer"></div>

JavaScript API

import { createEmptyState } from 'https://ui.scybud.com/js/ui.js';

createEmptyState({
  container: document.getElementById('feedContainer'),
  icon: '✉️',
  title: 'Your inbox is completely clear',
  description: 'New alerts will show up here.',
  actionText: 'Refresh Feed',
  onAction: () => { /* ... */ }
});

Config options

Param Default Notes
container required Element the empty state is appended into
icon "📭" Any emoji or short string
title "Nothing here yet" Short headline
description "" Only rendered if non-empty
actionText null Only renders a button if set
onAction null Click handler for the action button

Accessibility guidance

Baseline practices that apply across every Scybud UI component.

  • Prefer semantic HTML and native controls.
  • Keep all interactive elements reachable by keyboard.
  • Use color tokens that preserve contrast on dark backgrounds.
  • Document required ARIA roles only when native markup is insufficient.

Examples

Full working pages, not just snippets. Every example ships with the shared sidebar layout.

Contributing

How a new component gets added to Scybud UI.

  • Each component gets its own CSS file under components/<name>/.
  • Any JS behavior lives under js/utils/ or js/components/, and is re-exported from js/ui.js so consumers only ever import one file.
  • Follow the token system, no hardcoded colors, spacing, or radius values outside variables.css.
  • Add a matching section to this docs page using the Component Template pattern above.
  • If the component needs a full interactive demo, add a page under examples/ and register it in shared-layout.js.

Changelog

Dated record of additions and changes to Scybud UI.

2026

Initial public release of Scybud UI: tokens, layout, typography, buttons, modal, lightbox, empty state, and sidebar navigation.