Installation
Complete project setup first. Your configuration
must select react/base and include your Design System ID.
pnpm exec frontfriend download page -f react --primitive baseReview dependencies reported by the downloader and keep your source changes in version control.
Usage
import {
Page,
PageContainer,
PageContent,
PageContentMain,
} from "@/components/ui/page";
<div className="h-[420px] w-[700px] max-w-full overflow-auto">
<Page layout="main">
<PageContainer>
<PageContent>
<PageContentMain>
<div className="flex flex-col gap-4">
<h2 className="font-semibold text-xl">This is a page</h2>
<div className="h-24 rounded-lg border border-neutral-subtle" />
<div className="grid grid-cols-2 gap-4">
<div className="h-32 rounded-lg border border-neutral-subtle" />
<div className="h-32 rounded-lg border border-neutral-subtle" />
</div>
<div className="h-40 rounded-lg border border-neutral-subtle" />
</div>
</PageContentMain>
</PageContent>
</PageContainer>
</Page>
</div>; Examples
Main
import {
Page,
PageWrap,
PageInner,
PageContainer,
PageContent,
PageSide,
PageContentMain,
} from "@/components/ui/page";
import {
Navbar,
NavbarLeft,
NavbarCenter,
NavbarRight,
} from "@/components/ui/navbar";
import { Button } from "@/components/ui/button";
function Logo() {
return (
<div className="flex items-center gap-2">
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="text-brand-mid"
>
<rect width="32" height="32" rx="8" fill="currentColor" />
<path
d="M10 12h12M10 16h12M10 20h8"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
<span className="text-lg font-semibold">FrontFriend</span>
</div>
);
}
<Page>
<PageWrap>
<Navbar>
<NavbarLeft>
<Logo />
</NavbarLeft>
<NavbarCenter></NavbarCenter>
<NavbarRight>
<Button
variant="secondary"
icon="Phone"
iconPosition="suffix"
size="sm"
>
Contact us
</Button>
</NavbarRight>
</Navbar>
<PageInner>
<PageContainer>
<PageContent>
<PageSide></PageSide>
<PageContentMain></PageContentMain>
</PageContent>
</PageContainer>
</PageInner>
</PageWrap>
</Page>; Focus
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useBreakpoints, cn } from "@frontfriend/sdk/lib/react/utils";
import {
Page,
PageWrap,
PageInner,
PageContainer,
PageContent,
PageSide,
PageContentMain,
} from "@/components/ui/page";
import { Skeleton } from "@/components/ui/skeleton";
import {
Form,
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { CheckboxField } from "@/components/ui/checkbox-field";
import { Button } from "@/components/ui/button";
const FiltersSchema = z.object({
email: z
.string()
.email({ message: "Invalid email" })
.min(2, { message: "Email must be at least 2 characters" }),
password: z
.string()
.min(2, { message: "Password must be at least 2 characters" }),
});
function Logo() {
return (
<div className="flex items-center gap-2">
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="text-brand-mid"
>
<rect width="32" height="32" rx="8" fill="currentColor" />
<path
d="M10 12h12M10 16h12M10 20h8"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
<span className="text-lg font-semibold">FrontFriend</span>
</div>
);
}
export default function PageExample() {
const emptyValue = {
email: "",
string: "",
};
const form = useForm<z.infer<typeof FiltersSchema>>({
resolver: zodResolver(FiltersSchema),
defaultValues: emptyValue,
});
function onSubmit(values: z.infer<typeof FiltersSchema>) {
console.log(values);
}
const { isLg } = useBreakpoints();
return (
<Page layout="focus">
<PageWrap>
<PageInner>
<PageContainer>
<PageContent>
<PageSide>
<div className="flex flex-col items-start justify-start gap-6 max-h-[700px] w-full overflow-visible">
<Logo />
<div className="flex flex-col items-start gap-3 w-full">
<span className="text-xl font-semibold font-secondary">
Welcome👋
</span>
<span className="text-sm">
Please login to our Platform to discover all the features
</span>
</div>
<div className="relative">
<Skeleton
className={cn(
"rounded-3xl w-[460px] h-[600px] hidden",
isLg && "block",
)}
/>
</div>
</div>
</PageSide>
<PageContentMain>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col items-center gap-6 self-stretch max-h-full"
>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel variant="secondary">Email</FormLabel>
<FormControl>
<Input className="w-full" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel variant="secondary">Password</FormLabel>
<FormControl>
<Input className="w-full" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-between items-center w-full">
<CheckboxField>Remember me</CheckboxField>
<Button variant="link" size="sm" type="button">
Forgot your password?
</Button>
</div>
<Button
type="submit"
className="w-full shrink-0"
variant="main"
>
Sign in
</Button>
<div className="flex items-start gap-1 ">
<span className="text-sm leading-[14px]">
Don't have an account?
</span>{" "}
<Button size="sm" variant="link" type="button">
Sign up
</Button>
</div>
</form>
</Form>
</PageContentMain>
</PageContent>
</PageContainer>
</PageInner>
</PageWrap>
</Page>
);
} API reference
Frontfriend-owned props. Native HTML and inherited primitive props remain documented by Base UI.
Page
| Prop | Type | Default | Description |
|---|---|---|---|
layout | PageLayout | "main" |
PageContentMain
| Prop | Type | Default | Description |
|---|---|---|---|
noPadding | boolean | false |
PageInner
| Prop | Type | Default | Description |
|---|---|---|---|
noPadding | boolean | false |
Configuration determines the actual classes and available styling hooks. See Theming & component configuration before introducing a repeated local override.