Code Block
Syntax-highlighted code block with language icon, copy button, and optional scrollable or collapsible overflow. Async server component powered by shiki.
shikilucide-react
Preview
ts
import { z } from "zod"
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().int().positive(),
})
type User = z.infer<typeof userSchema>Installation
$ shadcn add https://ui.justinlevine.me/r/code-block.jsonUsage
import { CodeBlock } from "@/components/code-block"<CodeBlock code={myCode} language="ts" />Since this is an async server component, it must be rendered in a server context. Syntax highlighting happens at build time — no client-side JavaScript for highlighting.
Examples
Languages
TypeScript
ts
import { z } from "zod"
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().int().positive(),
})
type User = z.infer<typeof userSchema>CSS
css
@import "tailwindcss";
@theme {
--color-primary: oklch(0.7 0.15 200);
--color-secondary: oklch(0.6 0.12 280);
--radius-lg: 0.75rem;
}With title
File Title
schema.ts
import { z } from "zod"
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().int().positive(),
})
type User = z.infer<typeof userSchema>Custom Title
Theme tokens
@import "tailwindcss";
@theme {
--color-primary: oklch(0.7 0.15 200);
--color-secondary: oklch(0.6 0.12 280);
--radius-lg: 0.75rem;
}Overflow modes
Scrollable
tsx
import * as React from "react"
import { cn } from "@/lib/utils"
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "default" | "outline" | "ghost" | "link"
size?: "sm" | "default" | "lg" | "icon"
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", ...props }, ref) => {
return (
<button
ref={ref}
className={cn(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium",
"ring-offset-background transition-colors",
"focus-visible:outline-none focus-visible:ring-2",
"focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button }
export type { ButtonProps }Collapsible
tsx
import * as React from "react"
import { cn } from "@/lib/utils"
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "default" | "outline" | "ghost" | "link"
size?: "sm" | "default" | "lg" | "icon"
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", ...props }, ref) => {
return (
<button
ref={ref}
className={cn(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium",
"ring-offset-background transition-colors",
"focus-visible:outline-none focus-visible:ring-2",
"focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button }
export type { ButtonProps }Muted style
Muted
ts
import { z } from "zod"
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().int().positive(),
})
type User = z.infer<typeof userSchema>Muted + Collapsible
tsx
import * as React from "react"
import { cn } from "@/lib/utils"
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "default" | "outline" | "ghost" | "link"
size?: "sm" | "default" | "lg" | "icon"
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", ...props }, ref) => {
return (
<button
ref={ref}
className={cn(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium",
"ring-offset-background transition-colors",
"focus-visible:outline-none focus-visible:ring-2",
"focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button }
export type { ButtonProps }API Reference
CodeBlock
PropType
Notes
- Language icons via SVGL. Language icons are fetched from the SVGL API at build time and cached for 24 hours.
- Dual theme. Uses
github-lightandgithub-darkshiki themes for automatic light/dark mode support.