useUser
The useUser hook returns session-stable user information. These values are set once at initialization and do not change during the session.
Basic usage
Section titled “Basic usage”import { useUser } from "@usefractal/frac/web";
function UserInfo() { const { locale, userAgent } = useUser();
return ( <div> <p>Locale: {locale}</p> <p>Device: {userAgent.device.type}</p> <p>Touch: {userAgent.capabilities.touch ? "Yes" : "No"}</p> </div> );}Returns
Section titled “Returns”type UserState = { locale: string; userAgent: UserAgent;};
type UserAgent = { device: { type: "mobile" | "tablet" | "desktop" | "unknown"; }; capabilities: { hover: boolean; touch: boolean; };};locale
Section titled “locale”The user’s locale string in BCP 47 format (e.g., "en-US", "fr-FR", "ja-JP").
userAgent
Section titled “userAgent”Information about the user’s device and its capabilities.
userAgent.device.type
Section titled “userAgent.device.type”The type of device the user is on:
mobile- Mobile phonetablet- Tablet devicedesktop- Desktop or laptop computerunknown- Unable to determine device type
userAgent.capabilities.hover
Section titled “userAgent.capabilities.hover”Whether the device supports hover interactions (typically true for desktop, false for touch-only devices).
userAgent.capabilities.touch
Section titled “userAgent.capabilities.touch”Whether the device supports touch interactions.
Examples
Section titled “Examples”Localized Greeting
Section titled “Localized Greeting”import { useUser } from "@usefractal/frac/web";
function LocalizedGreeting() { const { locale } = useUser();
const greetings: Record<string, string> = { en: "Hello!", fr: "Bonjour!", es: "Hola!", de: "Hallo!", ja: "こんにちは!", };
const language = locale.split("-")[0]; const greeting = greetings[language] || greetings.en;
return <h1>{greeting}</h1>;}Date Formatting
Section titled “Date Formatting”import { useUser } from "@usefractal/frac/web";
function LocalizedDate({ date }: { date: Date }) { const { locale } = useUser();
const formattedDate = new Intl.DateTimeFormat(locale, { dateStyle: "full", timeStyle: "short", }).format(date);
return <time dateTime={date.toISOString()}>{formattedDate}</time>;}Number and Currency Formatting
Section titled “Number and Currency Formatting”import { useUser } from "@usefractal/frac/web";
function PriceDisplay({ amount, currency }: { amount: number; currency: string }) { const { locale } = useUser();
const formattedPrice = new Intl.NumberFormat(locale, { style: "currency", currency, }).format(amount);
return <span className="price">{formattedPrice}</span>;}Responsive Component
Section titled “Responsive Component”import { useUser } from "@usefractal/frac/web";
function ResponsiveLayout({ children }: { children: React.ReactNode }) { const { userAgent } = useUser();
const layoutClass = { mobile: "layout-compact", tablet: "layout-medium", desktop: "layout-full", unknown: "layout-full", }[userAgent.device.type];
return <div className={layoutClass}>{children}</div>;}Touch-Friendly Controls
Section titled “Touch-Friendly Controls”import { useUser } from "@usefractal/frac/web";
function Slider({ value, onChange }: { value: number; onChange: (v: number) => void }) { const { userAgent } = useUser();
// Use larger touch targets on touch devices const thumbSize = userAgent.capabilities.touch ? 44 : 20;
return ( <input type="range" value={value} onChange={(e) => onChange(Number(e.target.value))} style={{ height: thumbSize, cursor: userAgent.capabilities.hover ? "pointer" : "default", }} /> );}