Practical blocks

API Keys Table

Fictional keys with working reveal and copy controls.

API keys

Demo data

Try it, then make it yours

Forms use native validation and honest local feedback. The keys are fictional. These demos provide no backend authentication, storage, or key management.

Compose the block with the components from oscl-ui and import the package stylesheet.

Actual demo source

The file below includes the shared component previews and the BlockDemo function used here.

demos.tsx
"use client";
import Image from "next/image";
import {useState} from "react";
import {ArrowRight,Check,Layers} from "lucide-react";
import {Button,Input,Textarea,Badge,Checkbox,Switch,Card,CardHeader,CardContent,CardFooter,Tabs,TabsList,TabsTrigger,TabsContent,Dialog,DialogTrigger,DialogContent,DialogTitle,DialogDescription,Tooltip,CodeBlock,CopyButton,ApiKeyField,StatusIndicator,EmptyState} from "oscl-ui";
export function ComponentDemo({slug}:{slug:string}) {
 const [count,setCount]=useState(0);
 switch(slug) {
  case "button":return <div className="demo-stack"><div className="demo-row"><Button onClick={()=>setCount(c=>c+1)} trailingIcon={<ArrowRight size={16}/>}>Build something</Button><Button variant="outline" onClick={()=>setCount(c=>c+1)}>Your next idea</Button></div><div className="demo-row"><Button variant="secondary">Secondary</Button><Button variant="ghost">Ghost</Button><Button disabled>Disabled</Button></div><span className="demo-feedback" role="status">{count ? `Clicked ${count} ${count===1?"time":"times"}. Keep building.` : "Go on. Give it a click."}</span></div>;
  case "input":return <Input label="Your email" type="email" placeholder="you@example.com" description="A real label. A little extra context."/>;
  case "textarea":return <Textarea label="Your next idea" placeholder="What do you want to build?" rows={4}/>;
  case "badge":return <div className="demo-row"><Badge>Draft</Badge><Badge variant="success">Ready</Badge><Badge variant="warning">Review</Badge><Badge variant="error">Needs a fix</Badge></div>;
  case "checkbox":return <div className="demo-stack"><Checkbox label="Keep me in the loop" defaultChecked/><Checkbox label="A little less email, please"/></div>;
  case "switch":return <div className="demo-stack"><Switch label="Enable notifications" defaultChecked description="You can change your mind anytime."/><Switch label="Focus mode"/></div>;
  case "card":return <Card><CardHeader><Layers size={20}/><h3>Your next project</h3></CardHeader><CardContent><p>A little room for your next idea. Composable from the first line.</p></CardContent><CardFooter><Badge variant="success">Ready to build</Badge></CardFooter></Card>;
  case "tabs":return <Tabs defaultValue="overview"><TabsList aria-label="Workspace example"><TabsTrigger value="overview">Overview</TabsTrigger><TabsTrigger value="activity">Activity</TabsTrigger><TabsTrigger value="settings">Settings</TabsTrigger></TabsList><TabsContent value="overview">A little overview of everything you are building.</TabsContent><TabsContent value="activity">Your latest update: you tried the tabs.</TabsContent><TabsContent value="settings">Make this workspace feel like yours.</TabsContent></Tabs>;
  case "dialog":return <Dialog><DialogTrigger asChild><Button>Open a little dialog</Button></DialogTrigger><DialogContent><DialogTitle>A little space to focus</DialogTitle><DialogDescription>Keyboard focus stays here while this dialog is open. Press Escape or use the close button to return.</DialogDescription><Badge variant="success">You opened it</Badge></DialogContent></Dialog>;
  case "tooltip":return <Tooltip content="A little extra context. Keyboard focus works too."><Button variant="outline">Hover or focus me</Button></Tooltip>;
  case "code-block":return <CodeBlock language="tsx" filename="hello.tsx" code={'import { Button } from "oscl-ui";\n\n<Button>Build something</Button>'}/>;
  case "copy-button":return <div className="demo-stack"><code>Hello from OSCL</code><CopyButton value="Hello from OSCL" label="Copy message"/></div>;
  case "api-key-field":return <ApiKeyField value="oscl_demo_not_a_real_key" description="Fictional example. No real credentials."/>;
  case "status-indicator":return <div className="demo-stack"><StatusIndicator status="operational"/><StatusIndicator status="degraded"/><StatusIndicator status="outage"/><StatusIndicator status="unknown"/></div>;
  default:return <EmptyState icon={<Layers size={24}/>} title="Room for something new" description="Your first project starts with an idea."/>;
 }
}
export function BlockDemo({slug}:{slug:string}) {
 const [message,setMessage]=useState("");
 if(slug==="api-keys-table")return <div className="block-demo"><div className="demo-row spread"><h3>API keys</h3><Badge>Demo data</Badge></div><ApiKeyField value="oscl_demo_development_key" label="Development"/><ApiKeyField value="oscl_demo_preview_key" label="Preview"/></div>;
 const login=slug==="login-form";
 return <form className="block-demo" onSubmit={event=>{event.preventDefault();setMessage(login?"Validation passed. This local demo does not sign you in.":"Preferences saved for this preview. No server request was made.");}}><div className="block-brand"><Image src="/brand/oscl-symbol-dark.png" alt="" width="34" height="34"/><span>OSCL</span></div><h3>{login?"Welcome back.":"Make it your own."}</h3><p className="muted">{login?"A little space to build something good.":"A few small choices. A workspace that feels like you."}</p>{!login&&<Input label="Display name" name="name" defaultValue="Alex Builder" required maxLength={80}/>}<Input label="Email" name="email" type="email" placeholder="you@example.com" required/>{login?<Input label="Password" name="password" type="password" autoComplete="off" required minLength={8} description="Demo only. Use a fictional password."/>:<Switch label="Product updates" defaultChecked/>}<Button type="submit" trailingIcon={<ArrowRight size={16}/>}>{login?"Try sign in":"Save preferences"}</Button>{message&&<p role="status" className="block-message"><Check size={16}/>{message}</p>}</form>;
}