@luciodale/docs-ui-kit
v0.3.38
Published
Astro component library for documentation sites. Dark theme, orange accent.
Maintainers
Readme
@luciodale/docs-ui-kit
Astro component library for building documentation sites. Dark theme, orange accent, Tailwind CSS v4. Ships source .astro files and pre-compiled Tailwind utilities — your Astro project processes the components, the CSS works everywhere without @source hacks.
Install
npm install @luciodale/docs-ui-kitPeer dependency: astro >= 5.
Runtime dependency: shiki (build-time syntax highlighting in Astro frontmatter).
Setup in your Astro project
1. CSS
Create a global CSS file and import the theme + pre-compiled utilities:
/* src/styles/global.css */
@import "tailwindcss";
@import "@luciodale/docs-ui-kit/styles.css";
@import "@luciodale/docs-ui-kit/utilities.css";styles.css— Tailwind v4@themetokens (colors, fonts), base body styles (background: black; color: white), and custom utilities like.liquid-glass-borderutilities.css— Pre-compiled Tailwind utility classes used by all components (navbar, sidebar, code blocks, etc.). Ships with the package so you don't need@sourcedirectives pointing intonode_modules
Then import this CSS in your base layout's frontmatter (not a <style> tag):
---
import "../styles/global.css";
---2. Fonts
The theme uses Work Sans (body) and JetBrains Mono (code). Load them in your base layout's <head>:
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />3. SiteConfig
Define a config object that drives all layout components:
// src/config.ts
import type { SiteConfig } from "@luciodale/docs-ui-kit/types/config";
export const siteConfig: SiteConfig = {
title: "my-library",
description: "A short description of your library.",
siteUrl: "https://my-library-docs.pages.dev",
installCommand: "npm install my-library",
githubUrl: "https://github.com/you/my-library",
author: "Your Name",
// Optional:
// logoSrc: "/logo.svg",
// logoAlt: "My Library logo",
// ogImage: "/og.png",
// faviconSrc: "/favicon.ico",
// twitterHandle: "@you",
// copyright: "Your Name",
socialLinks: {
github: "https://github.com/you",
// linkedin: "https://linkedin.com/in/you",
},
navLinks: [
{ href: "/docs/getting-started", label: "Docs" },
{ href: "/demo/basic", label: "Demo" },
],
sidebarSections: [
{
title: "Getting Started",
links: [
{ href: "/docs/getting-started", label: "Introduction" },
{ href: "/docs/configuration", label: "Configuration" },
],
},
{
title: "Demos",
links: [
{ href: "/demo/basic", label: "Basic" },
],
},
],
};Types
SiteConfig
import type { SiteConfig } from "@luciodale/docs-ui-kit/types/config";| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Site/library name. Shown in navbar, footer, SEO. |
| description | string | Yes | Default meta description. Fallback for pages without their own. |
| siteUrl | string | Yes | Canonical base URL (e.g. https://docs.example.com). Used by SEO + sitemap. |
| installCommand | string | Yes | Shown in HeroSection with copy button. |
| githubUrl | string | Yes | Links to the repo from navbar. |
| socialLinks | { github: string; linkedin?: string } | Yes | Footer social icons. |
| navLinks | Array<{ href: string; label: string }> | Yes | Top navbar links. Active state based on currentPath.startsWith(href). |
| sidebarSections | Array<{ title: string; links: NavLink[] }> | Yes | Left sidebar groups. Also shown in mobile menu. |
| author | string | No | Used in SEO meta tags and JSON-LD structured data. |
| logoSrc | string | No | Image URL for navbar/footer. Falls back to title text. |
| logoAlt | string | No | Alt text for logo. Falls back to title. |
| ogImage | string | No | Path to default Open Graph image (1200x630). |
| faviconSrc | string | No | Path to favicon. |
| twitterHandle | string | No | @handle for Twitter Card meta tags. |
| copyright | string | No | Footer copyright text. Falls back to title. |
PropsTableRow
import type { PropsTableRow } from "@luciodale/docs-ui-kit/types/props";| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Prop name. |
| type | string | Yes | Type annotation string. |
| description | string | Yes | What the prop does. |
| defaultValue | string | No | Default value. Shows "—" if omitted. |
| required | boolean | No | Shows red asterisk if true. |
Components
All components are imported from @luciodale/docs-ui-kit/components/<Name>.astro.
Layout Components
DocsLayout
Three-column layout: left sidebar + content + right table of contents. Used for docs and demo pages.
---
import DocsLayout from "@luciodale/docs-ui-kit/components/DocsLayout.astro";
---
<DocsLayout config={siteConfig} currentPath={Astro.url.pathname}>
<!-- page content -->
</DocsLayout>| Prop | Type | Required | Description |
|---|---|---|---|
| config | SiteConfig | Yes | Site configuration object. |
| currentPath | string | Yes | Current URL pathname. Used for active link highlighting. |
Includes: Navbar (sticky, blur backdrop), Sidebar (sticky, collapsible sections, hidden on mobile), TableOfContents (auto-built from ContentSection components, hidden below xl breakpoint), Footer.
PageLayout
Simple layout without sidebars. Used for landing/home pages.
---
import PageLayout from "@luciodale/docs-ui-kit/components/PageLayout.astro";
---
<PageLayout config={siteConfig} currentPath="/">
<!-- page content -->
</PageLayout>Same props as DocsLayout. Includes: Navbar, Footer. No sidebar or TOC.
Content Components
ContentSection
Wraps a content section with an <h2> heading. Automatically registers in the right-side TableOfContents — no manual TOC config needed.
---
import ContentSection from "@luciodale/docs-ui-kit/components/ContentSection.astro";
---
<ContentSection label="Installation">
<p>Install the package...</p>
</ContentSection>
<ContentSection label="Quick Start">
<p>Create a manager...</p>
</ContentSection>| Prop | Type | Required | Description |
|---|---|---|---|
| label | string | Yes | Section heading text. Also appears in the TOC. |
| id | string | No | Custom anchor ID. Auto-generated from label if omitted (slugified). |
Renders: <section id="..." data-toc-label="..."><h2>...</h2><slot /></section> with scroll-mt-24 for smooth anchor scrolling past the sticky navbar.
SectionHeading
Standalone <h2> heading without TOC registration. Use when you want a heading that does NOT appear in the table of contents.
---
import SectionHeading from "@luciodale/docs-ui-kit/components/SectionHeading.astro";
---
<SectionHeading>My Heading</SectionHeading>
<SectionHeading class="text-xl">Smaller Heading</SectionHeading>| Prop | Type | Required | Description |
|---|---|---|---|
| class | string | No | Additional CSS classes. |
CodeBlock
Syntax-highlighted code block with copy button. Highlighting happens at build time via Shiki (zero client JS for highlighting). Uses vitesse-dark theme.
---
import CodeBlock from "@luciodale/docs-ui-kit/components/CodeBlock.astro";
---
<CodeBlock code="npm install my-lib" language="bash" filename="terminal" />
<CodeBlock
code={`const x: string = "hello";
console.log(x);`}
language="tsx"
filename="example.ts"
/>| Prop | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | The source code string. Leading/trailing whitespace is trimmed. |
| language | string | No | Shiki language ID. Default: "tsx". |
| filename | string | No | Shown in the header bar. Falls back to language. |
PropsTable
Renders a styled table for documenting component props or API options.
---
import PropsTable from "@luciodale/docs-ui-kit/components/PropsTable.astro";
import type { PropsTableRow } from "@luciodale/docs-ui-kit/types/props";
const rows: PropsTableRow[] = [
{ name: "url", type: "string", required: true, description: "WebSocket server URL." },
{ name: "debug", type: "boolean", defaultValue: "false", description: "Enable debug logging." },
];
---
<PropsTable title="Manager Options" rows={rows} />| Prop | Type | Required | Description |
|---|---|---|---|
| title | string | No | Optional heading above the table. |
| rows | Array<PropsTableRow> | Yes | Table data. See PropsTableRow type above. |
HeroSection
Landing page hero with title, description, install command (with copy button), and optional extra content via slot.
---
import HeroSection from "@luciodale/docs-ui-kit/components/HeroSection.astro";
---
<HeroSection
title="my-library"
description="A short tagline."
installCommand="npm install my-library"
>
<!-- Optional: extra content below the install command -->
<div class="flex gap-4">
<a href="/docs" class="rounded-lg bg-accent px-5 py-2.5 text-sm text-white">Get Started</a>
</div>
</HeroSection>| Prop | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Main heading (h1). |
| description | string | Yes | Subtitle paragraph. |
| installCommand | string | Yes | Shell command. Copy button copies this string. |
| logoSrc | string | No | Logo image above the title. |
| logoAlt | string | No | Alt text for logo. |
Callout
Info, warning, tip, or danger admonition boxes for calling out important information.
---
import Callout from "@luciodale/docs-ui-kit/components/Callout.astro";
---
<Callout type="info">This API is stable and ready for production.</Callout>
<Callout type="warning">This feature requires React 18+.</Callout>
<Callout type="tip" title="Performance">Use ref-counted subscriptions to avoid duplicate connections.</Callout>
<Callout type="danger">Calling dispose() is irreversible.</Callout>| Prop | Type | Required | Description |
|---|---|---|---|
| type | "info" \| "warning" \| "tip" \| "danger" | No | Default: "info". Controls color and icon. |
| title | string | No | Heading text. Defaults: "Note", "Warning", "Tip", "Danger". |
Renders a left-bordered aside with icon, title, and slot content. Supports links (<a>) and inline code (<code>) in the body.
FeatureList
Highlighted feature list with colored dots and keywords. Designed for landing pages and feature summaries.
---
import FeatureList from "@luciodale/docs-ui-kit/components/FeatureList.astro";
---
<FeatureList features={[
{ highlight: "Type-safe", description: "Full TypeScript support out of the box" },
{ highlight: "Lightweight", description: "Zero runtime overhead", color: "green" },
{ highlight: "Dark theme", description: "Built for modern documentation sites" },
]} />
<!-- Or set a global color for all items -->
<FeatureList
color="cyan"
features={[
{ highlight: "Fast", description: "Build-time syntax highlighting via Shiki" },
{ highlight: "Searchable", description: "Full-text search powered by Pagefind" },
]}
/>| Prop | Type | Required | Description |
|---|---|---|---|
| features | Array<FeatureItem> | Yes | List of feature items (see below). |
| color | FeatureColor | No | Default: "accent". Global color for all items. Overridden by per-item color. |
FeatureItem:
| Field | Type | Required | Description |
|---|---|---|---|
| highlight | string | Yes | Colored keyword/phrase. Rendered in bold with the active color. |
| description | string | No | Text after the highlight, separated by an em dash. |
| color | FeatureColor | No | Per-item color override. |
FeatureColor: "accent" | "blue" | "green" | "purple" | "yellow" | "cyan"
PackageInfo
Displays npm version, license, GitHub stars, and a bundlephobia link. Data is fetched at build time from the npm registry and GitHub API (3s timeout, graceful fallback).
---
import PackageInfo from "@luciodale/docs-ui-kit/components/PackageInfo.astro";
---
<PackageInfo packageName="@luciodale/react-socket" githubRepo="luciodale/react-socket" />| Prop | Type | Required | Description |
|---|---|---|---|
| packageName | string | Yes | npm package name. Used to fetch version + license from registry. |
| githubRepo | string | No | GitHub owner/repo. Used to fetch star count. If omitted, stars badge is hidden. |
Renders a row of styled badges: version (accent color, links to npm), license, GitHub stars (links to repo), bundlephobia link.
Search
SearchModal
Full-text search powered by Pagefind. Renders a search trigger button (for Navbar) + a dialog modal. Includes Cmd+K / Ctrl+K keyboard shortcut.
The component is automatically included in the Navbar — no manual placement needed. It loads Pagefind dynamically at runtime from /_pagefind/pagefind.js.
Consumer setup:
After building your Astro site, run Pagefind to generate the search index:
astro build && bunx pagefind --site dist/clientOr for static output:
astro build && bunx pagefind --site distAdd this to your package.json scripts:
{
"scripts": {
"build": "astro build && bunx pagefind --site dist/client"
}
}How it works:
- Desktop: compact search button with "Search" label +
Cmd+Kbadge, placed between nav links and GitHub icon - Mobile: small search icon button next to the hamburger menu
- Cmd+K / Ctrl+K opens a centered modal dialog with backdrop blur
- Pagefind
sub_resultsare flattened so each result links to a specific page section (anchor), not just the page - Results show section title, parent page name, and highlighted excerpt (up to 10 results)
- Clicking a result navigates to the page + section anchor and closes the modal
- Search input is debounced (150ms)
- If Pagefind is not indexed, shows a helpful setup message
No additional imports needed — SearchModal is included by DocsLayout and PageLayout via the Navbar.
SEO Component
SEO
Renders all meta tags, Open Graph, Twitter Cards, JSON-LD structured data, and breadcrumbs. Place in <head>.
---
import SEO from "@luciodale/docs-ui-kit/components/SEO.astro";
---
<head>
<SEO
config={siteConfig}
title="Getting Started"
description="How to install and configure the library."
currentPath={Astro.url.pathname}
type="article"
/>
</head>| Prop | Type | Required | Description |
|---|---|---|---|
| config | SiteConfig | Yes | Site configuration. Provides siteUrl, author, ogImage, etc. |
| title | string | Yes | Page title. On / it's used as-is; elsewhere formatted as Title \| SiteName. |
| description | string | No | Page description. Falls back to config.description. |
| currentPath | string | Yes | URL pathname. Used for canonical URL and breadcrumbs. |
| type | "website" \| "article" | No | Default: "website". Use "article" for docs pages (generates TechArticle JSON-LD). |
| publishedDate | string | No | ISO date string for article:published_time. |
| modifiedDate | string | No | ISO date string for article:modified_time. |
| noindex | boolean | No | Default: false. Set true to add noindex, nofollow. |
What it renders:
<title>with smart formatting<meta name="description">,<meta name="author">,<meta name="robots"><link rel="canonical">(absolute URL fromsiteUrl+currentPath)<link rel="icon">(iffaviconSrcset)- Open Graph:
og:type,og:url,og:title,og:description,og:site_name,og:locale,og:image(with dimensions + alt) - Twitter Card:
twitter:card,twitter:title,twitter:description,twitter:image,twitter:site,twitter:creator - Article meta:
article:published_time,article:modified_time,article:author <meta name="theme-color" content="#000000">,<meta name="color-scheme" content="dark">- JSON-LD
WebSiteschema (on homepage) orTechArticleschema (on article pages) - JSON-LD
BreadcrumbListauto-generated from URL path segments (on non-root pages)
Icon Components
GithubIcon / LinkedInIcon
SVG icon components. Used internally by Navbar and Footer, but exported for custom use.
---
import GithubIcon from "@luciodale/docs-ui-kit/components/GithubIcon.astro";
import LinkedInIcon from "@luciodale/docs-ui-kit/components/LinkedInIcon.astro";
---
<GithubIcon class="w-6 text-white" />
<LinkedInIcon class="w-6 text-white/50" />| Prop | Type | Required | Description |
|---|---|---|---|
| class | string | No | CSS classes. Default: "w-5 text-white". |
Typical page structure
Base layout (create in your project)
---
// src/layouts/Base.astro
import SEO from "@luciodale/docs-ui-kit/components/SEO.astro";
import { siteConfig } from "../config";
import "../styles/global.css";
type Props = { title: string; description?: string; type?: "website" | "article" };
const { title, description, type = "website" } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<link rel="sitemap" href="/sitemap-index.xml" />
<SEO config={siteConfig} title={title} description={description} currentPath={Astro.url.pathname} type={type} />
</head>
<body>
<slot />
</body>
</html>Docs layout wrapper (create in your project)
---
// src/layouts/DocsPage.astro
import DocsLayout from "@luciodale/docs-ui-kit/components/DocsLayout.astro";
import { siteConfig } from "../config";
import Base from "./Base.astro";
type Props = { title: string; description?: string };
const { title, description } = Astro.props;
---
<Base title={title} description={description} type="article">
<DocsLayout config={siteConfig} currentPath={Astro.url.pathname}>
<slot />
</DocsLayout>
</Base>Home page
---
// src/pages/index.astro
import PageLayout from "@luciodale/docs-ui-kit/components/PageLayout.astro";
import HeroSection from "@luciodale/docs-ui-kit/components/HeroSection.astro";
import FeatureList from "@luciodale/docs-ui-kit/components/FeatureList.astro";
import { siteConfig } from "../config";
import Base from "../layouts/Base.astro";
export const prerender = true;
---
<Base title={siteConfig.title}>
<PageLayout config={siteConfig} currentPath="/">
<HeroSection
title={siteConfig.title}
description={siteConfig.description}
installCommand={siteConfig.installCommand}
>
<FeatureList features={[
{ highlight: "Type-safe", description: "Full TypeScript support" },
{ highlight: "Lightweight", description: "Zero runtime dependencies", color: "green" },
{ highlight: "Fast", description: "Build-time syntax highlighting", color: "cyan" },
]} />
</HeroSection>
</PageLayout>
</Base>Docs page
---
// src/pages/docs/getting-started.astro
import CodeBlock from "@luciodale/docs-ui-kit/components/CodeBlock.astro";
import ContentSection from "@luciodale/docs-ui-kit/components/ContentSection.astro";
import DocsPage from "../../layouts/DocsPage.astro";
export const prerender = true;
---
<DocsPage title="Getting Started" description="Learn how to install and use the library.">
<ContentSection label="Installation">
<CodeBlock code="npm install my-library" language="bash" filename="terminal" />
</ContentSection>
<ContentSection label="Quick Start">
<p class="text-white/60 mb-4">Create an instance:</p>
<CodeBlock code={`import { MyLib } from "my-library";\nconst lib = new MyLib();`} language="tsx" filename="app.ts" />
</ContentSection>
</DocsPage>Each ContentSection automatically appears in the right-side table of contents. No manual TOC array needed.
Demo page with React island
---
// src/pages/demo/basic.astro
import ContentSection from "@luciodale/docs-ui-kit/components/ContentSection.astro";
import { MyDemo } from "../../components/MyDemo"; // React component
import DocsPage from "../../layouts/DocsPage.astro";
export const prerender = true;
---
<DocsPage title="Basic Demo" description="Live interactive demo.">
<ContentSection label="Demo">
<MyDemo client:load />
</ContentSection>
</DocsPage>React islands require @astrojs/react in your Astro project. The docs-ui-kit itself has zero React dependency.
OG Image Generator
Generate a 1200x630 Open Graph preview image for link sharing (Slack, Twitter, Discord, etc.). Reads public/logo.svg for the logo and installCommand from src/config.ts for the npm package name. Outputs public/og-image.png.
bun run og-image <path-to-docs-site>Example from the docs-ui-kit root:
bun run og-image ../react-socket/packages/docsThen set ogImage in the docs site config:
export const siteConfig: SiteConfig = {
// ...
ogImage: "/og-image.png",
};The SEO component picks up ogImage and renders og:image, og:image:width, og:image:height, and twitter:image tags automatically.
Color palette
Defined in theme.css via Tailwind v4 @theme tokens:
| Token | Value | Usage |
|---|---|---|
| --color-accent | #ef4723 | Primary accent. Links, active indicators, buttons. Tailwind: text-accent, bg-accent, border-accent. |
| --color-accent-hover | #d63d1f | Hover state for accent. Tailwind: bg-accent-hover. |
| --color-primary | #42170c | Deep brown. Available but rarely used directly. |
| --color-secondary | #6b7280 | Gray. |
| --color-surface | #f9fafb | Light surface (for light-mode contexts). |
| --color-border | #e5e7eb | Light border. |
| --color-muted | #848d9f | Muted text. |
Body: background: black, color: white. All components use white/ opacity variants for text hierarchy (text-white/70 body text, text-white/60 secondary, text-white/40 labels, text-white/30 decorative).
Responsive behavior
| Breakpoint | Left Sidebar | Content | Right TOC | Mobile Menu |
|---|---|---|---|---|
| < md (mobile) | Hidden | Full width | Hidden | Hamburger → slide-in from right |
| md – xl | Visible (256px) | Flex | Hidden | N/A |
| >= xl | Visible (256px) | Flex | Visible (176px) | N/A |
View Transitions compatibility
All client-side scripts (<script> in components) re-initialize on the astro:after-swap event, so everything works with Astro View Transitions out of the box.
License
MIT
