Meet Frontfriend.Your brand. Your rules. Your agents, connected.Explore what’s new

Page

Interactive preview

Rendered from the shared Frontfriend stories with React Base, the same preview Studio shows. Styling comes from your Design System; the code below is native to Radix UI.

Installation

Complete project setup first. Your configuration must select react/radix and include your Design System ID.

pnpm exec frontfriend download page -f react --primitive radix

Review 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 Radix 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.