Getting Started
Blocks
Now.ts UI
Introduction
Now.ts UI is a component library built on top of shadcn/ui to help you build fullstack React applications faster. It provides pre-built components for authentication, forms, dialogs, and more.
Components are available via the standard shadcn CLI:
pnpm dlx shadcn@latest add https://ui.nowts.app/r/<component>.json
For example, to install the Submit Button component, you can run:
pnpm dlx shadcn@latest add https://ui.nowts.app/r/submit-button.json
Featured Components
TanStack Form
Create Account
TanStack Form with Zod validation
"use client"
import { toast } from "sonner"
import { z } from "zod"
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
getInputFieldProps,
useForm,
} from "@/components/ui/tanstack-form"
const accountSchema = z.object({
email: z.string().email("Invalid email"),
password: z.string().min(8, "Password must be at least 8 characters"),
})
export function TanstackFormDemo() {
const form = useForm({
schema: accountSchema,
defaultValues: {
email: "",
password: "",
},
onSubmit: async (values) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success("Account created successfully!")
console.log(values)
},
})
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="text-lg font-semibold">Create Account</CardTitle>
<CardDescription>TanStack Form with Zod validation</CardDescription>
</CardHeader>
<CardContent>
<Form form={form} className="space-y-4">
<FormField form={form} name="email">
{(field) => (
<FormItem field={field} form={form}>
<FormLabel>Email</FormLabel>
<FormControl>
<Input
{...getInputFieldProps(field)}
type="email"
placeholder="you@example.com"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
</FormField>
<FormField form={form} name="password">
{(field) => (
<FormItem field={field} form={form}>
<FormLabel>Password</FormLabel>
<FormControl>
<Input
{...getInputFieldProps(field)}
type="password"
placeholder="••••••••"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
</FormField>
<Button type="submit" className="w-full">
Create Account
</Button>
</Form>
</CardContent>
</Card>
)
}
Dialog Manager
Dialog Manager
Programmatic dialogs with confirm, input, and custom variants
"use client"
import { Trash2 } from "lucide-react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { dialogManager } from "@/registry/nowts/blocks/dialog-manager/dialog-manager"
export function DialogManagerDemo() {
const handleConfirmDialog = () => {
dialogManager.confirm({
title: "Delete Account",
description:
"Are you sure you want to delete your account? This action cannot be undone.",
action: {
label: "Delete",
variant: "destructive",
onClick: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success("Account deleted")
},
},
icon: Trash2,
style: "centered",
})
}
const handleInputDialog = () => {
dialogManager.input({
title: "Create Project",
description: "Enter a name for your new project",
input: {
label: "Project Name",
placeholder: "my-awesome-project",
defaultValue: "",
},
action: {
label: "Create",
onClick: async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success(`Project "${value}" created`)
},
},
})
}
const handleConfirmTextDialog = () => {
dialogManager.confirm({
title: "Delete Everything",
description: "This will permanently delete all your data.",
confirmText: "DELETE",
action: {
label: "Delete",
variant: "destructive",
onClick: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success("All data deleted")
},
},
})
}
return (
<Card className="p-6">
<div className="mb-6">
<h3 className="text-lg font-semibold">Dialog Manager</h3>
<p className="text-muted-foreground text-sm">
Programmatic dialogs with confirm, input, and custom variants
</p>
</div>
<div className="grid gap-2">
<Button
onClick={handleConfirmDialog}
variant="default"
className="w-full"
>
Confirm Dialog
</Button>
<Button
onClick={handleInputDialog}
variant="secondary"
className="w-full"
>
Input Dialog
</Button>
<Button
onClick={handleConfirmTextDialog}
variant="outline"
className="w-full"
>
Confirm with Text
</Button>
</div>
</Card>
)
}
Form Management
Form Management
Edit and see the sticky save bar appear (CMD+S to save)
"use client"
import { toast } from "sonner"
import { z } from "zod"
import { Card } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { FormManagement } from "@/registry/nowts/blocks/form-management/form-management"
import { FormAutoSaveStickyBar } from "@/registry/nowts/blocks/form-management/form-management-sticky-bar"
import { useZodForm } from "@/components/ui/extended-form"
const profileSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email address"),
bio: z.string().max(200, "Bio must be less than 200 characters"),
})
export function FormManagementDemo() {
const form = useZodForm({
schema: profileSchema,
defaultValues: {
name: "John Doe",
email: "john@example.com",
bio: "Full-stack developer passionate about building great products",
},
})
const onSubmit = async (data: z.infer<typeof profileSchema>) => {
await new Promise((resolve) => setTimeout(resolve, 1500))
toast.success("Profile saved successfully!")
form.reset(data)
}
return (
<Card className="p-6">
<div className="mb-6">
<h3 className="text-lg font-semibold">Form Management</h3>
<p className="text-muted-foreground text-sm">
Edit and see the sticky save bar appear (CMD+S to save)
</p>
</div>
<FormManagement form={form} onSubmit={onSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="name">Name</Label>
<Input id="name" {...form.register("name")} />
{form.formState.errors.name && (
<p className="text-destructive text-sm">
{form.formState.errors.name.message}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" {...form.register("email")} />
{form.formState.errors.email && (
<p className="text-destructive text-sm">
{form.formState.errors.email.message}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="bio">Bio</Label>
<Textarea
id="bio"
{...form.register("bio")}
placeholder="Tell us about yourself"
rows={3}
/>
{form.formState.errors.bio && (
<p className="text-destructive text-sm">
{form.formState.errors.bio.message}
</p>
)}
</div>
<FormAutoSaveStickyBar />
</FormManagement>
</Card>
)
}
You can explore all components here or view the source code on GitHub.
Build Your SaaS in Days, Not Months
NOW.TS is the Next.js 15 boilerplate with everything you need to launch your SaaS—auth, payments, database, and AI-ready infrastructure.
Learn more about NOW.TS