mdxui
Type-aware components for rendering MDXLD documents
MDXUI: Components for MDXLD Types
MDXUI provides type-aware components that know how to render different MDXLD $type values - whether it's a LandingPage, Site, App, API docs, or Documentation.
What is MDXUI?
MDXUI maps MDXLD semantic types to appropriate UI components:
---
$type: LandingPage
title: Welcome to Our Product
---
{/* MDXUI automatically renders LandingPage with Hero, Features, etc. */}The same content with a different $type renders differently:
---
$type: Documentation
title: Welcome to Our Product
---
{/* Same content, but renders as docs with navigation, search, etc. */}Type-Aware Rendering:
LandingPage→ Hero, Features, Pricing, TestimonialsDocumentation→ Sidebar, Search, TOC, BreadcrumbsBlogPost→ Article layout, Author info, Related postsProduct→ Gallery, Specs, Reviews, Buy buttonAPI→ Endpoints, Parameters, Examples, Try-itApp→ Full-page layout with routing and stateSite→ Multi-page with navigation and footer
Also provides:
- Layout Components: Container, Grid, Flex, Stack, Section
- Primitive Components: Button, Card, Input, Badge
- Semantic HTML: Proper HTML5 elements for each type
- Accessibility: ARIA attributes and keyboard navigation
- Themeable: Customize appearance per type
Installation
pnpm install mdxuiQuick Start
Automatic Type-Based Rendering
MDXUI automatically applies the right layout based on $type:
---
$type: LandingPage
title: My Product
features:
- Fast Performance
- Easy to Use
- Secure
pricing:
- name: Free
price: $0
- name: Pro
price: $29
---
# {data.title}
The best product for your needs.MDXUI sees $type: LandingPage and automatically:
- Wraps content in landing page layout
- Renders
data.featuresas feature cards - Renders
data.pricingas pricing table - Adds appropriate semantic HTML and meta tags
Manual Component Usage
You can also use components directly:
import { Button, Card, Grid } from 'mdxui'
<Grid cols={3}>
<Card title="Feature 1">
<Button>Learn More</Button>
</Card>
<Card title="Feature 2">
<Button>Learn More</Button>
</Card>
<Card title="Feature 3">
<Button>Learn More</Button>
</Card>
</Grid>Note: In MDX files, the markdown/content itself is automatically the default export - you don't need to explicitly export components or the page itself. Just write markdown and use components inline.
Type-Based Rendering
MDXUI provides specialized rendering for each MDXLD type:
$type: LandingPage
Renders with hero, features, pricing, testimonials:
---
$type: LandingPage
title: Welcome to Product
subtitle: The best solution for your needs
cta:
text: Get Started
url: /signup
features:
- icon: ⚡
title: Fast
description: Lightning-fast performance
- icon: 🔒
title: Secure
description: Bank-level security
pricing:
- name: Starter
price: $0
features: [10 projects, 100 GB]
- name: Pro
price: $29
features: [Unlimited, 1 TB]
---
# {data.title}
{data.subtitle}Renders as: Hero section + Features grid + Pricing table + CTA
$type: Documentation
Renders with sidebar, search, table of contents:
---
$type: Documentation
title: Getting Started
category: Guides
sidebar:
- Installation
- Configuration
- Usage
---
# {data.title}
This guide will help you get started.
## Installation
Install the package...Renders as: Sidebar navigation + Content area + Search + TOC
$type: BlogPost
Renders as article with metadata:
---
$type: BlogPost
title: Introduction to GraphQL
author: Jane Developer
date: 2025-10-27
tags: [graphql, api, tutorial]
---
# {data.title}
By {data.author} on {data.date}
Content here...Renders as: Article header + Author info + Reading time + Related posts
$type: Product
Renders with gallery, specs, reviews:
---
$type: Product
name: Widget Pro
price: 99.99
images:
- /products/widget-1.jpg
- /products/widget-2.jpg
specs:
- Dimensions: 10x5x3 inches
- Weight: 2.5 lbs
reviews:
- author: John
rating: 5
text: Amazing product!
---
# {data.name}
${data.price}
Premium widget with advanced features.Renders as: Image gallery + Price + Specs table + Reviews + Buy button
$type: API
Renders with endpoint browser, try-it console:
---
$type: API
title: Users API
baseUrl: https://api.example.com
endpoints:
- method: GET
path: /users
description: List all users
params:
- name: limit
type: number
- method: POST
path: /users
description: Create user
---
# {data.title}
Base URL: {data.baseUrl}
## Endpoints
API documentation here...Renders as: Endpoint list + Parameters + Examples + Try-it console
$type: App
Renders as full application with routing:
---
$type: App
title: My Dashboard
routes:
- path: /
component: Home
- path: /settings
component: Settings
nav:
- Dashboard
- Analytics
- Settings
---
# {data.title}
Full app content...Renders as: App shell + Router + Navigation + Content area
$type: Site
Renders as multi-page website:
---
$type: Site
title: Company Website
pages:
- Home
- About
- Contact
nav:
logo: /logo.svg
links:
- Home: /
- About: /about
footer:
copyright: 2025 Company
links:
- Privacy: /privacy
---
# {data.title}
Site content...Renders as: Header + Nav + Pages + Footer
Same Content, Different Types
The same MDX content can render multiple ways depending on $type:
---
$type: LandingPage # or Documentation, BlogPost, Product, etc.
title: Welcome
description: Learn about our product
features:
- Fast
- Secure
- Scalable
---
# {data.title}
{data.description}
Our product is amazing!As LandingPage: Hero with CTA + Feature cards + Marketing layout
As Documentation: Sidebar + Content + Search + Doc layout
As BlogPost: Article format + Author + Date + Blog layout
As Product: Product page + Images + Buy button + E-commerce layout
Layout Components
Container
Center and constrain content width:
<Container>
<h1>Page Title</h1>
<p>Content is centered with max width</p>
</Container>
<Container size="small">Narrow</Container>
<Container size="large">Wide</Container>Grid
Responsive grid layouts:
<Grid cols={3}>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</Grid>
<Grid cols={2} gap="large">
<Card>Item 1</Card>
<Card>Item 2</Card>
</Grid>Flex
Flexbox layouts:
<Flex direction="row" align="center" justify="space-between">
<div>Left</div>
<div>Right</div>
</Flex>
<Flex direction="column" gap="medium">
<Card>Item 1</Card>
<Card>Item 2</Card>
</Flex>Stack
Vertical spacing:
<Stack spacing="large">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Stack>Primitive Components
Button
<Button>Default</Button>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="danger">Delete</Button>
<Button href="/docs">Link</Button>
<Button size="small">Small</Button>
<Button size="large">Large</Button>Card
<Card title="Title">
Card content goes here
</Card>
<Card title="With Icon" icon="📚">
Content
</Card>
<Card variant="bordered">
Bordered card
</Card>Badge
<Badge>Default</Badge>
<Badge variant="success">New</Badge>
<Badge variant="warning">Beta</Badge>
<Badge variant="error">Deprecated</Badge>Feature Components
Hero
<Hero
title="Welcome to Our Platform"
subtitle="Build amazing things faster"
cta={<Button variant="primary" size="large">Get Started</Button>}
image="/hero.png"
/>Features
<Features
items={[
{
icon: "⚡",
title: "Fast",
description: "Lightning-fast performance"
},
{
icon: "🔒",
title: "Secure",
description: "Built-in security"
},
{
icon: "🌍",
title: "Global",
description: "Worldwide CDN"
}
]}
/>Pricing
<Pricing
plans={[
{
name: 'Free',
price: '$0',
features: ['10 projects', '100 GB storage'],
cta: <Button>Start Free</Button>
},
{
name: 'Pro',
price: '$29',
features: ['Unlimited projects', '1 TB storage'],
cta: <Button variant="primary">Upgrade</Button>,
highlighted: true
}
]}
/>Testimonials
<Testimonials
items={[
{
quote: "Amazing product!",
author: "Jane Developer",
role: "CTO at TechCorp",
avatar: "/avatars/jane.jpg"
}
]}
/>Stats
<Stats
items={[
{ label: 'Users', value: '10,245', change: '+12%' },
{ label: 'Revenue', value: '$45.2K', change: '+23%' },
{ label: 'Conversion', value: '3.2%', change: '-2%' }
]}
/>Content Components
Callout
<Callout type="info">
This is an informational message
</Callout>
<Callout type="warning">
Warning message
</Callout>
<Callout type="error">
Error message
</Callout>
<Callout type="success">
Success message
</Callout>Tabs
<Tabs>
<Tab title="Installation">
## Installation
\`\`\`bash
pnpm install mdxui
\`\`\`
</Tab>
<Tab title="Usage">
## Usage
Import components
</Tab>
</Tabs>Accordion
<Accordion>
<AccordionItem title="What is MDX?">
MDX combines Markdown with JSX
</AccordionItem>
<AccordionItem title="How to get started?">
Install and import components
</AccordionItem>
</Accordion>Code Block
<CodeBlock
language="typescript"
code={\`
function greet(name: string) {
return \`Hello, \${name}!\`
}
\`}
showLineNumbers
highlightLines={[2]}
/>Form Components
Input
<Input
label="Name"
placeholder="Enter your name"
required
/>
<Input
type="email"
label="Email"
placeholder="[email protected]"
/>Select
<Select
label="Country"
options={[
{ value: 'us', label: 'United States' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'ca', label: 'Canada' }
]}
/>Textarea
<Textarea
label="Message"
rows={4}
placeholder="Enter your message"
/>Checkbox
<Checkbox label="I agree to terms" />
<Checkbox label="Subscribe to newsletter" defaultChecked />Theming
Default Theme
import { ThemeProvider } from 'mdxui'
export default function Layout({ children }) {
return (
<ThemeProvider>
{children}
</ThemeProvider>
)
}Custom Theme
import { createTheme, ThemeProvider } from 'mdxui'
const theme = createTheme({
colors: {
primary: '#007bff',
secondary: '#6c757d',
success: '#28a745',
warning: '#ffc107',
error: '#dc3545',
info: '#17a2b8',
},
fonts: {
body: 'system-ui, sans-serif',
heading: 'Georgia, serif',
mono: 'Consolas, monospace',
},
spacing: {
small: '0.5rem',
medium: '1rem',
large: '2rem',
},
})
export default function Layout({ children }) {
return (
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
)
}Tailwind Integration
Use with Tailwind CSS:
// tailwind.config.js
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./node_modules/mdxui/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
colors: {
primary: '#007bff',
},
},
},
}Components automatically use Tailwind classes:
<Button className="bg-primary text-white">
Custom Styled Button
</Button>Accessibility
All components include:
- Semantic HTML: Proper HTML5 elements
- ARIA Attributes: Labels, roles, and states
- Keyboard Navigation: Tab, Enter, Escape, Arrow keys
- Focus Management: Visible focus indicators
- Screen Reader Support: Descriptive labels
Example:
<Button
aria-label="Close dialog"
aria-pressed={isPressed}
>
Close
</Button>
<Tabs aria-label="Navigation tabs">
<Tab title="Home">Home content</Tab>
<Tab title="About">About content</Tab>
</Tabs>Responsive Design
Components are mobile-first and responsive:
<Grid cols={1} md={2} lg={3}>
<Card>Mobile: 1 col, Tablet: 2 cols, Desktop: 3 cols</Card>
</Grid>
<Flex direction="column" md="row">
<div>Stacks on mobile, horizontal on tablet+</div>
</Flex>Advanced Usage
Composition
Build complex UIs:
<Container>
<Hero
title="Welcome"
cta={<Button>Get Started</Button>}
/>
<Section>
<Grid cols={3}>
<Card><Features /></Card>
<Card><Pricing /></Card>
<Card><Testimonials /></Card>
</Grid>
</Section>
<Section>
<Tabs>
<Tab title="Docs"><Documentation /></Tab>
<Tab title="Examples"><Examples /></Tab>
</Tabs>
</Section>
</Container>Custom Components
Extend MDXUI components:
import { Button as BaseButton } from 'mdxui'
export function CustomButton({ children, ...props }) {
return (
<BaseButton
{...props}
className="custom-styles"
>
{children}
</BaseButton>
)
}Use Cases
Documentation Sites
<Container>
<Tabs>
<Tab title="Getting Started">
<Callout type="info">Install the package</Callout>
<CodeBlock language="bash" code="pnpm install" />
</Tab>
<Tab title="API Reference">
<Accordion>
<AccordionItem title="Functions">...</AccordionItem>
<AccordionItem title="Types">...</AccordionItem>
</Accordion>
</Tab>
</Tabs>
</Container>Landing Pages
<Hero title="Product Name" cta={<Button>Sign Up</Button>} />
<Features items={features} />
<Pricing plans={plans} />
<Testimonials items={testimonials} />
<Footer />Blogs
<Container size="small">
<article>
# Blog Post Title
<Callout type="info">
Published on {date}
</Callout>
Content here...
<Grid cols={2}>
<Card>Related Post 1</Card>
<Card>Related Post 2</Card>
</Grid>
</article>
</Container>