Phone Mockup
nexvyn/phone-mockupFreeComponent
A device-frame illustration with side buttons, dynamic island, and a cropped/scrolled variant for showcasing app screens.
Live preview
live · rendered by the registry
Rendered by nexvyn on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.nexvyn.dev/r/phone-mockup.jsonSource
1'use client'23import { forwardRef, type ComponentPropsWithoutRef, type ReactNode } from 'react'4import { cn } from '@/lib/utils'56const mockupChassisVariants = {7 black: {8 frame: 'bg-(--color-foreground)',9 button: 'bg-(--color-foreground)',10 },11 white: {12 frame: 'bg-(--color-card)',13 button: 'bg-(--color-card)',14 },15 accent: {16 frame:17 'bg-(--color-accent) dark:bg-[color-mix(in_srgb,var(--color-accent)_60%,var(--color-card))]',18 button:19 'bg-(--color-accent) dark:bg-[color-mix(in_srgb,var(--color-accent)_60%,var(--color-card))]',20 },21} as const2223type MockupChassisVariant = keyof typeof mockupChassisVariants2425const CHASSIS_ASPECT_RATIO = 70.6 / 146.62627type PhoneMockupCardProps = Readonly<28 ComponentPropsWithoutRef<'div'> & {29 variant?: MockupChassisVariant30 visibleRatio?: number31 showDynamicIsland?: boolean32 }33>3435const sideControlClass = (color: string) => cn('absolute w-0.5 rounded-l-sm', color)3637function SideControls({38 frame,39}: Readonly<{40 frame: (typeof mockupChassisVariants)[MockupChassisVariant]41}>) {42 return (43 <>44 <div45 className={cn(sideControlClass(frame.button), 'top-[15.5%] -left-0.5 h-[3.2%]')}46 aria-hidden="true"47 />48 <div49 className={cn(sideControlClass(frame.button), 'top-[21%] -left-0.5 h-[7.2%]')}50 aria-hidden="true"51 />52 <div53 className={cn(sideControlClass(frame.button), 'top-[30.5%] -left-0.5 h-[7.2%]')}54 aria-hidden="true"55 />56 <div57 className={cn(58 sideControlClass(frame.button),59 'top-[23%] -right-0.5 h-[11.5%] rounded-l-none rounded-r-sm',60 )}61 aria-hidden="true"62 />63 </>64 )65}6667function MockupScreen({68 children,69 showDynamicIsland,70}: Readonly<{71 children: ReactNode72 showDynamicIsland: boolean73}>) {74 return (75 <div className="relative h-full w-full overflow-hidden rounded-[2.5rem] bg-black">76 <div className="absolute inset-[3.5px] overflow-hidden rounded-[2.3rem] bg-white">77 <div className="relative h-full w-full">{children}</div>78 {showDynamicIsland && (79 <div80 className="absolute top-[9px] left-1/2 z-20 h-5 w-[66px] -translate-x-1/2 rounded-full bg-black"81 aria-hidden="true"82 >83 <div84 className="absolute top-1/2 right-[5px] block h-2 w-2 shrink-0 -translate-y-1/2 rounded-full bg-(--color-muted)/40"85 aria-hidden="true"86 />87 </div>88// … truncated
Files it writes
More from nexvyn
All 40 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | nexvyn | Components | Free | 1 dep | |
| Action Buttonaction-button | nexvyn | Components | Free | 3 deps · 4 files | |
| Adaptive Actionsadaptive-actions | nexvyn | Components | Free | 1 dep | |
| AI Inputai-input | nexvyn | Components | Free | 1 dep · 2 files | |
| Badgebadge | nexvyn | Components | Free | 2 deps · 2 files | |
| Bars Themebars-theme | nexvyn | Components | Free | 1 dep · 3 files | |
| Bounce Sidebarbounce-sidebar | nexvyn | Components | Free | 1 dep · 2 files | |
| Breadcrumbsbreadcrumbs | nexvyn | Components | Free | 1 dep · 2 files |
