Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Mobile

Install Prompt

Mobile

Install Prompt React component for Tailwind CSS v4

Hero HeaderLarge Title Header
Live props
Content
appName
appIcon
description
Appearance
variant
tone
color
radius
Layout
placement
position
safeArea
desktop
Behavior
platform
delay3000ms
dismissDays14 days
storageKey
showOnIOS
showOnDesktop
State
defaultOpen
Code
import { InstallPrompt } from "@/components/ui/install-prompt"

<InstallPrompt />
  1. Home
  2. Components
  3. Mobile
  4. Install Prompt
Pro

Install Prompt React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React PWA install prompt: the browser's install dialog in Chrome and Edge, and an Add to Home Screen guide on iPhone and Mac.

A few seconds after the page can be installed, a slim card with the app's icon, name and an Install button slides up from the bottom (or drops from the top) and stays out of the way: it never takes focus and the page keeps working under it. On Android and desktop Chrome or Edge, Install opens the browser's own install dialog; the button shows a spinner while it is open, and once the app is installed the card says Installed with a check for two seconds and leaves. On an iPhone or iPad, where browsers have no such dialog, Install opens a bottom sheet with three numbered steps (tap Share, choose Add to Home Screen, tap Add), each with the icon you will look for, and on an iPhone an arrow at the bottom of the sheet bobs twice toward Safari's share button. On a Mac with Safari the card shows the Add to Dock steps inline. The × (named Not now) hides it for dismissDays and remembers that in localStorage; closing the sheet by dragging it down, tapping outside or pressing Escape counts the same. On a desktop Chrome window the banner is a 380px card in the bottom end corner. With the keyboard, Tab reaches Install and ×, Enter or Space presses them, and in the sheet (a centered dialog from 768px up) Tab stays inside and Escape closes it, returning focus to the button that opened it. Installed or already running as an app, it renders nothing. The outcome is announced to screen readers. Under reduced motion it fades instead of sliding.

Install Prompt is a Pro React component in the React mobile components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add install-prompt, together with UIProvider, Button, Drawer, useControllableState, useMediaQuery and 3 more and the npm packages motion and lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add install-prompt

Install Prompt is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import InstallPrompt from @/components/ui/install-prompt.

// app/layout.tsx: mount it once in the root layout, the browser offers the install only once and early
import type { ReactNode } from "react"
import { InstallPrompt } from "@/components/ui/install-prompt"

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <InstallPrompt
          appName="Northwind CRM"
          appIcon="/icon-192.png"
          description="Open it right from your home screen, even offline."
          labels={{
            notNow: "Maybe later",
            iosSteps: ["Tap Share in the bottom bar", "Choose Add to Home Screen", "Tap Add"],
          }}
        />
      </body>
    </html>
  )
}

Props

  • appNamedefault ""
    string

    The app's name, used in the titles ("Install Northwind CRM") and for the letter tile. Empty falls back to labels.fallbackName ("this app").

  • appIcondefault ""
    string | ReactNode

    The icon: an image src (shown 48px with 12px corners, use your 192px manifest icon) or an element. Empty draws a tile in the tone with the first letter of appName.

  • descriptiondefault ""
    string

    One line under the title: why installing helps. Truncated in the slim banner, wrapped in the sheet and the card.

  • screenshots
    string[]

    Sheet variant: a horizontal rail of screenshots (h-72, 9:16, snapping) between the title and the buttons, keyboard scrollable.

  • variantdefault "banner"
    "banner" | "sheet" | "card"

    banner: a slim floating card pinned to placement, like a Smart App Banner (on iPhone its Install opens the guide sheet; on a Mac it shows the steps inline). sheet: a bottom sheet with details, a centered dialog from 768px up. card: an inline card you place yourself (a settings page), always visible while the app can be installed.

  • placementdefault "bottom"
    "bottom" | "top"

    The banner's edge. Bottom sits above a bottom tab bar and a sticky CTA bar (--bottom-bar-offset, --cta-bar-offset) and the home indicator; top sits under the notch, or under --install-prompt-top when you set it (a fixed header).

  • positiondefault "fixed"
    "fixed" | "absolute"

    fixed pins the banner to the viewport (and turns it into a 380px card at the bottom end on desktop); absolute pins it inside the nearest positioned parent (a phone frame, a panel).

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The Install button and the letter tile. Keep neutral in an app; brand fits a marketing page.

  • colordefault ""
    string

    Any CSS color for the Install button and the letter tile, replacing the tone.

  • radiusdefault "md"
    "sm" | "md" | "lg"

    Corners of the card and the floating banner: 12, 16 or 24px.

  • platformdefault "auto"
    "auto" | "chromium" | "ios" | "macos-safari" | "unsupported"

    auto detects it: chromium once the browser has offered an install (beforeinstallprompt), ios on iPhone and iPad in any browser, macos-safari on Safari 17+ for Mac; in-app browsers and everything else are unsupported and render nothing. Force one for demos and QA; a forced chromium without a real event makes Install resolve "unavailable".

  • delaydefault 3000
    number

    Milliseconds after it becomes possible before the banner or sheet shows, so it never greets people on arrival. Ignored while open is controlled and by the card.

  • dismissDaysdefault 14
    number

    How long Not now hides it, in days. 0 hides it for this session only (sessionStorage).

  • storageKeydefault "install-prompt"
    string

    The localStorage key that remembers Not now (a timestamp). Empty keeps it in memory; with storage blocked it lasts the session.

  • showOnIOSdefault true
    boolean

    Show the Add to Home Screen guide on iPhone and iPad.

  • showOnDesktopdefault true
    boolean

    Show it in Chrome and Edge on a computer and the Add to Dock guide in Safari for Mac.

  • defaultOpendefault false
    boolean

    Open the banner or sheet at once (no delay, a previous Not now ignored). An initially open banner skips its entrance.

  • open
    boolean

    Controlled open state of the banner or sheet; pair it with onOpenChange. It still renders nothing where there is no install path.

  • onOpenChange
    (open: boolean) => void

    Called when it opens after the delay and when it closes (Not now, installed, the sheet dismissed).

  • onInstall
    (outcome: "accepted" | "dismissed" | "unavailable") => void

    The result of Install in Chromium: accepted, dismissed in the browser dialog (the prompt cannot be shown again until the browser offers it again), or unavailable (no pending event).

  • onDismiss
    () => void

    Not now, the ×, Got it in the guide, or the sheet closed by drag, tap outside or Escape.

  • safeAreadefault true
    boolean

    Pad the banner off the notch, the home indicator and the rounded side edges (env(safe-area-inset-*)).

  • desktopdefault "dialog"
    "dialog" | "sheet"

    What the sheet (and the iPhone guide) becomes at 768px and up: a centered dialog, or the same bottom sheet capped at 420px.

  • container
    HTMLElement | null

    Portal target of the sheet (default document.body). A transformed or contain:layout element keeps the sheet inside it, like a phone frame.

  • labels
    Partial<InstallPromptLabels>

    Every string: install "Install", notNow "Not now", title(name) "Install {name}", iosTitle(name) "Add {name} to your Home Screen", iosSteps ["Tap Share in the toolbar", "Scroll and choose Add to Home Screen", "Tap Add"], macTitle(name) "Add {name} to the Dock", macSteps ["Choose File in the menu bar", "Choose Add to Dock"], installed "Installed", fallbackName "this app", close "Close", done "Got it", installedAnnouncement(name) "{name} was installed", screenshots "Screenshots", screenshot(i, n) "Screenshot {i} of {n}", addGlyph "Add", fileGlyph "File". Defaults in DEFAULT_INSTALL_PROMPT_LABELS.

  • classNames
    Partial<Record<"icon" | "content" | "title" | "description" | "screenshots" | "steps" | "step" | "actions" | "install" | "dismiss", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the root: the banner's pinned wrapper, the card, or the sheet's content.

Parts

  • useInstallPrompt

    hook

    The same engine without the UI, for your own button (a profile menu item). One store per page listens for beforeinstallprompt and appinstalled from the first call on, so call it (or mount InstallPrompt) in the root layout: the event fires once, early. canInstall is true while the browser prompt is pending (chromium) or the guide applies (ios, macos-safari). Signature: (options?: { platform?: "auto" | InstallPlatform; storageKey?: string; dismissDays?: number }) => { platform: InstallPlatform; canInstall: boolean; isStandalone: boolean; installed: boolean; dismissed: boolean; promptInstall: () => Promise<"accepted" | "dismissed" | "unavailable">; dismiss: () => void; reset: () => void }.

  • DEFAULT_INSTALL_PROMPT_LABELS

    constant

    The English defaults, to spread and override. Type: InstallPromptLabels.

Examples

iPhone guide

The only path on iOS: three steps with the icons to look for, and an arrow toward Safari's share button.

Install sheet with screenshots

Chromium: the sheet shows what you get, then Install opens the browser's own dialog.

Card in settings

variant="card" sits in the page and stays while the app can be installed.

Top banner, brand tone

placement="top" under the status bar, for a marketplace's landing screen.

Safari on a Mac

The Add to Dock guide as a card: File, then Add to Dock.

Your own button

useInstallPrompt drives a menu item; the flags are this browser's real state.

Dependencies

motionlucide-reactui-configbuttondraweruse-controllable-stateuse-media-queryuse-persisted-statemotiontones

Files

  • components/ui/install-prompt.tsx

FAQ

Is the React Install Prompt component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Install Prompt?

Run npx wingo-ui@latest add install-prompt. It also adds the Wingo UI items it builds on (UIProvider, Button, Drawer, useControllableState, useMediaQuery and 3 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/install-prompt.

How does Install Prompt behave on phones?

On an iPhone or iPad, where browsers have no such dialog, Install opens a bottom sheet with three numbered steps (tap Share, choose Add to Home Screen, tap Add), each with the icon you will look for, and on an iPhone an arrow at the bottom of the sheet bobs twice toward Safari's share button.

See also

DrawerNotification BannerOnboarding CarouselusePersistedStatehookuseMediaQueryhookButton

More React mobile components

Large Title HeaderPicker WheelPull To RefreshSwipe DeckSwipeable TabsHero Header
All 15 React mobile components

Articles using this component

  • Nextjs PWA Without next-pwa: Offline Page and App Shell

    Mobile UI in React · Nov 5, 2026 · 12 min read

  • React Native vs PWA in 2026: Which One Do You Need?

    Comparisons and alternatives · Oct 16, 2026 · 12 min read

  • React Onboarding Flow: Slides, Permissions, Install

    Build it: screens and apps · Oct 16, 2026 · 9 min read

  • React PWA Install Prompt for Chrome, Edge and iPhone

    Mobile UI in React · Oct 9, 2026 · 9 min read

PreviousHero HeaderNext Large Title Header

Thursday, Sep 24, 2026

Hi, Emma

Collected today$12,480.00+8% vs yesterday
Outstanding$7,315.203 overdue invoices

Activity

  • Invoice #2026-0412Acme Corp · paid today$4,250.00
  • Order #1042UPS · out for delivery4:05 PM
  • Quote #Q-2026-118Northwind Logistics · sent$18,900.00
  • Greenleaf PharmacyInvoice 12 days overdue$7,315.20
  • Order #1041Pickup locker, Downtown · collectedyesterday
4:40
HomeClientsAddInbox4Profile
platform auto → chromium (simulated)banner · closeddelay 3000msdismissDays 14storageKey “install-prompt”position fixeddesktop dialogsafeAreashowOnIOSshowOnDesktopnot dismissed