Shadcn/UI Website Markup

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Website Markup Using Shadcn/UI

Shadcn/UI is not an npm package, but a collection of components that can be copied, based on Radix UI Primitives and Tailwind CSS. Components are added to the project via CLI — the source code ends up directly in the repository and can be modified without forks. This fundamentally distinguishes Shadcn/UI from traditional libraries.

Initialization

npx shadcn@latest init

The CLI asks about style (default/new-york), base color, and utilities alias. The configuration is saved to components.json:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "src/styles/globals.css",
    "baseColor": "slate",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  }
}

Adding components:

npx shadcn@latest add button card dialog form input select table tabs

Each command creates a file in src/components/ui/.

Color System via CSS Variables

/* src/styles/globals.css */
@import "tailwindcss";

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222 47% 11%;
    --card: 0 0% 100%;
    --card-foreground: 222 47% 11%;
    --popover: 0 0% 100%;
    --popover-foreground: 222 47% 11%;
    --primary: 221 83% 53%;       /* #2563eb */
    --primary-foreground: 0 0% 100%;
    --secondary: 210 40% 96%;
    --secondary-foreground: 222 47% 11%;
    --muted: 210 40% 96%;
    --muted-foreground: 215 16% 47%;
    --accent: 210 40% 96%;
    --accent-foreground: 222 47% 11%;
    --destructive: 0 84% 60%;
    --destructive-foreground: 0 0% 100%;
    --border: 214 32% 91%;
    --input: 214 32% 91%;
    --ring: 221 83% 53%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 222 47% 7%;
    --foreground: 210 40% 98%;
    --card: 222 47% 11%;
    --card-foreground: 210 40% 98%;
    --popover: 222 47% 11%;
    --popover-foreground: 210 40% 98%;
    --primary: 217 91% 60%;
    --primary-foreground: 0 0% 100%;
    --secondary: 217 33% 17%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217 33% 17%;
    --muted-foreground: 215 20% 65%;
    --accent: 217 33% 17%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 63% 31%;
    --destructive-foreground: 210 40% 98%;
    --border: 217 33% 17%;
    --input: 217 33% 17%;
    --ring: 217 91% 60%;
  }
}

Out-of-the-Box Components: Usage Examples

Dialog with Form

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';

const ContactDialog = () => (
  <Dialog>
    <DialogTrigger asChild>
      <Button>Contact Us</Button>
    </DialogTrigger>
    <DialogContent className="sm:max-w-md">
      <DialogHeader>
        <DialogTitle>Get in Touch</DialogTitle>
        <DialogDescription>
          Fill out the form and we'll respond within 24 hours.
        </DialogDescription>
      </DialogHeader>
      <div className="flex flex-col gap-4 py-4">
        <div className="flex flex-col gap-2">
          <Label htmlFor="name">Name</Label>
          <Input id="name" placeholder="John Doe" />
        </div>
        <div className="flex flex-col gap-2">
          <Label htmlFor="email">Email</Label>
          <Input id="email" type="email" placeholder="[email protected]" />
        </div>
      </div>
      <DialogFooter>
        <Button type="submit" className="w-full">Send</Button>
      </DialogFooter>
    </DialogContent>
  </Dialog>
);

Form with React Hook Form + Zod

import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';

const formSchema = z.object({
  email: z.string().email('Invalid email'),
  name: z.string().min(2, 'Minimum 2 characters'),
  subject: z.string().min(5, 'Minimum 5 characters'),
});

type FormValues = z.infer<typeof formSchema>;

const LeadForm = () => {
  const form = useForm<FormValues>({ resolver: zodResolver(formSchema) });

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-5">
        <FormField
          control={form.control}
          name="name"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Name</FormLabel>
              <FormControl>
                <Input placeholder="John Doe" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" placeholder="[email protected]" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit" className="w-full">
          Submit
        </Button>
      </form>
    </Form>
  );
};

Cards with Tabs

import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';

const PricingTabs = () => (
  <Tabs defaultValue="monthly" className="mx-auto max-w-2xl">
    <TabsList className="grid w-full grid-cols-2">
      <TabsTrigger value="monthly">Monthly</TabsTrigger>
      <TabsTrigger value="annual">Annual</TabsTrigger>
    </TabsList>
    <TabsContent value="monthly">
      <Card>
        <CardHeader>
          <CardTitle>Monthly Subscription</CardTitle>
          <CardDescription>Pay each month, cancel anytime.</CardDescription>
        </CardHeader>
        <CardContent>
          {/* Plan content */}
        </CardContent>
      </Card>
    </TabsContent>
    <TabsContent value="annual">
      <Card>
        <CardHeader>
          <CardTitle>Annual Subscription</CardTitle>
          <CardDescription>Save 20% compared to monthly plans.</CardDescription>
        </CardHeader>
        <CardContent>
          {/* Plan content */}
        </CardContent>
      </Card>
    </TabsContent>
  </Tabs>
);

Component Customization

Since the component code is in the project, you can modify it directly:

// src/components/ui/button.tsx — add a variant
const buttonVariants = cva(
  'inline-flex items-center justify-center ...',
  {
    variants: {
      variant: {
        default: '...',
        // Add a new variant
        gradient: 'bg-gradient-to-r from-brand-500 to-violet-600 text-white hover:opacity-90',
      },
    },
  }
);

Updating Components

# Check for updates
npx shadcn@latest diff

# Update a specific component
npx shadcn@latest add button --overwrite

Timeline

Shadcn/UI initialization and basic theme setup: 1–2 hours. Adding and customizing needed components: 2–4 hours. Landing page with Shadcn/UI + Tailwind + React: 1–2 days. Shadcn/UI is well-suited for SaaS products, admin panels, and any projects where you need professional UI with full control over component code.