Frontend
Component architecture, design system, styling conventions, and accessibility standards for Royal Glow.
Frontend
The frontend is server-first: components are React Server Components by default, and 'use client' is added only when browser APIs, state, or event handlers are needed. WCAG 2.1 AA and a Lighthouse Accessibility score of 100 are hard CI gates.
Component Architecture
The structure under apps/web/src/ separates routes, owned UI primitives, feature components, and framework-glue libraries.
This page covers the customer web app (apps/web → theroyalglow.in). The
admin portal is a separate Next.js app at apps/admin (served from
admin.theroyalglow.in, root-path routes with no /admin prefix) — its pages,
admin components, and admin data helpers all live under apps/admin/src/, not
in apps/web. apps/web only keeps lib/admin-redirect.ts, which 301-redirects
legacy theroyalglow.in/admin/* URLs to the subdomain.
Design System
Design Tokens
Tailwind CSS v4 design tokens are defined in apps/web/src/styles/globals.css.
Prop
Type
Typography
Prop
Type
Spacing & Layout
- Max content width:
1278px(max-w-[1278px]) - Horizontal padding:
px-5(20px) on mobile,px-8on desktop - Mobile-first: customer pages designed for 375px–428px first
shadcn/ui Components
Components are copy-pasted into components/ui/ — you own 100% of the code. Built on Radix UI primitives for production-tested accessibility.
Key components in use:
Button,Input,Label,Select,TextareaDialog,Sheet,Popover,TooltipBadge,Card,Separator,SkeletonTabs,AccordionCalendar,DatePicker
Booking Dialog
The booking dialog is a 4-step modal that opens over the homepage. It is never a separate page — it's always a modal overlay.
Step 1 — Branch, date & time
Branch selector plus a date and time-slot picker.
Step 2 — Service type & category
Salon/SPA toggle and category selection (one service type per booking).
Step 3 — Services
Service multi-select with a running total.
Step 4 — Summary & submission
Review and submit the booking.
Entry points:
- Homepage "Book Now" button
/?book=1deep-link (auto-opens dialog)/?book=1&utm_source=gmb(dialog + GMB attribution)/?book=1&utm_source=walkin(dialog + walk-in attribution)
The dialog has a full focus trap, aria-modal="true", and Escape key handling. It uses BookingDialogProvider (React context) to share open/close state across the page.
Animation
motion (motion.dev) handles all animations:
import { motion } from 'motion/react'
// Page transitions
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, ease: 'easeOut' }}
>
// Staggered list reveals
const container = {
hidden: { opacity: 0 },
show: { opacity: 1, transition: { staggerChildren: 0.1 } }
}All animations respect prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
/* motion handles this automatically via its built-in hook */
}Accessibility Standards
WCAG 2.1 AA compliance is non-negotiable. Lighthouse Accessibility = 100 is a hard CI gate.
<button>for actions (never<div onClick>)type="button"on all buttons not inside a formaria-labelon icon-only buttons- Visible focus ring (
focus-visible:ring-2) - Keyboard navigation support
- Every
<input>has a<label>with matchinghtmlFor/id aria-required="true"on required fieldsaria-describedbylinking input to error message<fieldset>+<legend>for grouped fields
aria-live="polite"on booking availability updatesaria-live="polite"on loading states (use the<output>element)role="alert"on error messages- Focus management on modal open/close
- Normal text: 4.5:1 minimum
- Large text (18px+ or 14px+ bold): 3:1 minimum
- UI components and graphical objects: 3:1 minimum
PWA
The app is installable as a Progressive Web App:
manifest.ts— app name, icons, theme colour, display modesw.js— service worker for offline supportServiceWorkerRegistrar— registers the service worker on first load- Offline page at
/offline— shows when user is offline
Offline capabilities:
- Service menu and prices (cached on first visit)
- Contact information and address
- Booking history (cached)
Performance Targets
Prop
Type
Coding Conventions
- Files:
kebab-case.tsfor utilities,PascalCase.tsxfor React components - Server Components by default — only add
'use client'when needed - Zero business logic in components — presentation only
- No
any— TypeScript strict mode enforced by Biome - Single quotes, no semicolons — Biome formatter
- Import sorting — handled automatically by Biome
Related Pages
Pages & Routes
Every route these components render
Conventions
Cross-cutting money, date, and layer rules
Tech Stack
The UI and tooling choices behind the frontend
Was this page helpful?