elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMemory
- useNetwork
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
- useVibrate
- useVirtualKeyboard
- useWakeLock
- useWebSocket
utilities
state
- useBoolean
- useControllableState
- useCookie
- useCookies
- useCounter
- useDefault
- useDisclosure
- useField
- useHash
- useList
- useLocalStorage
- useMap
- useMask
- useMergedRef
- useObject
- useOffsetPagination
- useQueue
- useRafState
- useRefState
- useSessionStorage
- useSet
- useStateHistory
- useStep
- useStorage
- useToggle
- useUrlSearchParam
- useUrlSearchParams
- useWizard
user
sensors
- useDeviceMotion
- useDeviceOrientation
- useHotkeys
- useIdle
- useInfiniteScroll
- useIntersectionObserver
- useKeyboard
- useKeyPress
- useKeysPressed
- useMouse
- useMutationObserver
- useOrientation
- usePageLeave
- useParallax
- usePerformanceObserver
- useResizeObserver
- useScroll
- useScrollIntoView
- useScrollTo
- useSwipe
- useTextSelection
- useVisibility
- useWindowEvent
- useWindowFocus
- useWindowScroll
- useWindowSize
Complete payment
Enter your payment method
import { useBrowserLocation } from '@siberiacancode/reactuse';
import {
ArrowLeftIcon,
AtSignIcon,
CheckIcon,
CreditCardIcon,
LandmarkIcon,
WalletIcon
} from 'lucide-react';
type PaymentMethod = 'bank' | 'card' | 'paypal';
const PAYMENT_METHODS = [
{
id: 'card',
title: 'Card',
description: 'Pay with Visa or Mastercard',
icon: CreditCardIcon
},
{
id: 'paypal',
title: 'PayPal',
description: 'Use your PayPal wallet',
icon: WalletIcon
},
{
id: 'bank',
title: 'Bank transfer',
description: 'Pay from your bank account',
icon: LandmarkIcon
}
] as const;
const Demo = () => {
const location = useBrowserLocation();
const step = Number(location.value.searchParams.get('step') ?? 1);
const selectedMethod = location.value.searchParams.get('method') ?? 'card';
const email = location.value.searchParams.get('email') ?? '';
const currentMethod =
PAYMENT_METHODS.find((method) => method.id === selectedMethod) ?? PAYMENT_METHODS[0];
const updateSearch = (params: Record<string, number | string>) => {
const searchParams = new URLSearchParams(location.value.search);
Object.entries(params).forEach(([key, value]) => {
searchParams.set(key, String(value));
});
location.push(`?${searchParams.toString()}`);
};
const onPaymentMethodChange = (method: PaymentMethod) => updateSearch({ step: 1, method, email });
const onEmailChange = (email: string) => updateSearch({ email });
const onCompletePayment = () => updateSearch({ step: 2, method: selectedMethod, email });
return (
<section className='flex w-full max-w-md min-w-0 flex-col gap-5 p-4'>
{step === 1 && (
<>
<div className='flex flex-col gap-1'>
<h3>Complete payment</h3>
<p className='text-muted-foreground text-sm'>Enter your payment method</p>
</div>
<div className='flex flex-col gap-2'>
{PAYMENT_METHODS.map((method) => {
const Icon = method.icon;
const isSelected = selectedMethod === method.id;
return (
<label
key={method.id}
className='border-border hover:bg-muted/50 has-[:checked]:border-foreground/30 has-[:checked]:bg-muted/50 relative flex min-w-0 cursor-pointer items-center gap-3 rounded-xl border p-4 text-left transition-colors'
>
<input
checked={isSelected}
className='absolute! top-4 right-4'
name='method'
type='radio'
onChange={() => onPaymentMethodChange(method.id)}
/>
<div className='bg-card flex size-10 items-center justify-center rounded-full border'>
<Icon className='size-4' />
</div>
<span className='flex min-w-0 flex-1 flex-col gap-1 pr-6'>
<span className='text-sm'>{method.title}</span>
<span className='text-muted-foreground text-xs break-words'>
{method.description}
</span>
</span>
</label>
);
})}
</div>
<div className='relative'>
<AtSignIcon className='pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 opacity-50' />
<input
className='w-full pl-8!'
placeholder='you@example.com'
type='email'
value={email}
onChange={(event) => onEmailChange(event.target.value)}
/>
</div>
<div className='flex justify-end'>
<button disabled={!email} type='button' onClick={onCompletePayment}>
Pay now
</button>
</div>
</>
)}
{step === 2 && (
<div className='flex flex-col gap-4'>
<div className='border-border bg-card flex flex-col items-center gap-4 rounded-2xl border px-6 py-8 text-center'>
<div className='flex size-14 items-center justify-center rounded-full bg-green-500/10 text-green-500'>
<CheckIcon className='size-8' />
</div>
<div className='flex flex-col items-center gap-2'>
<h4>Payment successful</h4>
<p className='text-muted-foreground max-w-xs text-sm break-words'>
Your order is confirmed and the receipt has been sent to {email}.
</p>
</div>
<div className='bg-muted/50 flex w-full min-w-0 flex-col gap-2 rounded-xl p-4 text-left'>
<div className='flex items-center justify-between gap-3 text-sm'>
<span className='text-muted-foreground'>Payment method</span>
<span className='text-foreground font-medium'>{currentMethod.title}</span>
</div>
<div className='flex items-center justify-between gap-3 text-sm'>
<span className='text-muted-foreground'>Email</span>
<span className='text-foreground min-w-0 text-right font-medium break-all'>
{email}
</span>
</div>
</div>
</div>
<div className='flex justify-start'>
<button data-variant='outline' type='button' onClick={() => location.back()}>
<ArrowLeftIcon className='size-4' /> Back
</button>
</div>
</div>
)}
</section>
);
};
export default Demo;
This hook uses window.location browser api to provide enhanced functionality. Make sure to check for compatibility with different browsers when using this api
Installation
pnpm add @siberiacancode/reactuseUsage
const { value, push, back, forward, go } = useBrowserLocation();Type Declarations
export interface BrowserLocationState {
/** URL hash including # */
hash?: string;
/** URL host */
host?: string;
/** URL hostname */
hostname?: string;
/** Full URL */
href?: string;
/** Number of entries in the session history */
length?: number;
/** URL origin */
origin?: string;
/** URL pathname */
pathname?: string;
/** URL port */
port?: string;
/** URL protocol */
protocol?: string;
/** URL search string */
search?: string;
/** URL search parameters */
searchParams: URLSearchParams;
/** Browser history state */
state?: unknown;
}
export interface UseBrowserLocationReturn {
/** Current browser location state */
value: BrowserLocationState;
/** Go back in history */
back: () => void;
/** Go forward in history */
forward: () => void;
/** Move by history delta */
go: (delta: number) => void;
/** Navigate to a new URL and push a history entry */
push: (url: string | URL, state?: unknown, title?: string) => void;
/** Navigate to a new URL and replace current history entry */
replace: (url: string | URL, state?: unknown, title?: string) => void;
}API
Returns
UseBrowserLocationReturnContributors
ddebabin
Last updated on