Compare commits
57 Commits
@formbrick
...
@formbrick
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ad948039 | ||
|
|
bcecdc0f3d | ||
|
|
273aad391e | ||
|
|
b0554757df | ||
|
|
3a5e297302 | ||
|
|
f6d7a023cd | ||
|
|
cbd74936ca | ||
|
|
9f902354bb | ||
|
|
5954a22ff3 | ||
|
|
69320e8119 | ||
|
|
a51c884e7f | ||
|
|
4a87ebbec3 | ||
|
|
03bd1107cf | ||
|
|
b45a32343e | ||
|
|
334d95fe2a | ||
|
|
7e24c065f0 | ||
|
|
83f3df4e81 | ||
|
|
2335c72234 | ||
|
|
6d2b26b391 | ||
|
|
23fd92f85c | ||
|
|
17b8bb1324 | ||
|
|
515b23859a | ||
|
|
cabe59dcea | ||
|
|
ed5b1cc263 | ||
|
|
d8a7d1a72e | ||
|
|
013fec0fe0 | ||
|
|
5bd09c13b6 | ||
|
|
47dd1d04de | ||
|
|
69985f5f39 | ||
|
|
e0d0458d7f | ||
|
|
a977cc403b | ||
|
|
ec695df017 | ||
|
|
99dd6478d2 | ||
|
|
0070f9c69d | ||
|
|
c834cbf8ce | ||
|
|
8535986ae8 | ||
|
|
8cf06c6ea5 | ||
|
|
43e6e4ad91 | ||
|
|
3fe3ca7ee4 | ||
|
|
d215371ec4 | ||
|
|
7e63da2977 | ||
|
|
fc58e9badf | ||
|
|
7c77a36ca1 | ||
|
|
3550a51cea | ||
|
|
0f638c3f6b | ||
|
|
4a8e1c563d | ||
|
|
32afef77ea | ||
|
|
a3db36fef5 | ||
|
|
0a17676981 | ||
|
|
74b1cb0687 | ||
|
|
3444f5b828 | ||
|
|
e2f625cd02 | ||
|
|
af5c9c8785 | ||
|
|
1c962433f3 | ||
|
|
d8d2ac115d | ||
|
|
104a3d22ff | ||
|
|
0eadbfce9d |
51
.env.docker
Normal file
@@ -0,0 +1,51 @@
|
||||
########################################################################
|
||||
# ------------ MANDATORY (CHANGE ACCORDING TO YOUR SETUP) ------------#
|
||||
########################################################################
|
||||
|
||||
|
||||
############
|
||||
# Basics #
|
||||
############
|
||||
|
||||
NEXTAUTH_SECRET=RANDOM_STRING
|
||||
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
# This should always be localhost:3000 (or whatever port your app is running on)
|
||||
NEXTAUTH_URL_INTERNAL=http://localhost:3000
|
||||
|
||||
DATABASE_URL='postgresql://postgres:postgres@postgres:5432/postgres?schema=public'
|
||||
|
||||
################
|
||||
# Mail Setup #
|
||||
################
|
||||
|
||||
# Necessary if email verification and password reset are enabled.
|
||||
# See optional configurations below if you want to disable these features.
|
||||
|
||||
# MAIL_FROM=noreply@example.com
|
||||
# SMTP_HOST=localhost
|
||||
# SMTP_PORT=1025
|
||||
# SMTP_SECURE_ENABLED=0 # Enable for TLS (port 465)
|
||||
# SMTP_USER=smtpUser
|
||||
# SMTP_PASSWORD=smtpPassword
|
||||
|
||||
|
||||
########################################################################
|
||||
# ------------------------------ OPTIONAL -----------------------------#
|
||||
########################################################################
|
||||
|
||||
# Uncomment the variables you would like to use and customize the values.
|
||||
|
||||
#####################
|
||||
# Disable Features #
|
||||
#####################
|
||||
|
||||
# Email Verification. If you enable Email Verification you have to setup SMTP-Settings, too.
|
||||
NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED=1
|
||||
|
||||
# Password Reset. If you enable Password Reset functionality you have to setup SMTP-Settings, too.
|
||||
NEXT_PUBLIC_PASSWORD_RESET_DISABLED=1
|
||||
|
||||
# Signup. Disable the ability for new users to create an account.
|
||||
# NEXT_PUBLIC_SIGNUP_DISABLED=1
|
||||
55
.env.example
Normal file
@@ -0,0 +1,55 @@
|
||||
########################################################################
|
||||
# ------------ MANDATORY (CHANGE ACCORDING TO YOUR SETUP) ------------#
|
||||
########################################################################
|
||||
|
||||
|
||||
############
|
||||
# Basics #
|
||||
############
|
||||
|
||||
NEXTAUTH_SECRET=RANDOM_STRING
|
||||
|
||||
# Set this to your public-facing URL, e.g., https://example.com
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
# This should always be localhost:3000 (or whatever port your app is running on)
|
||||
NEXTAUTH_URL_INTERNAL=http://localhost:3000
|
||||
|
||||
DATABASE_URL='postgresql://postgres:postgres@localhost:5432/postgres?schema=public'
|
||||
|
||||
# For Docker Compose Production Setup use this Database URL:
|
||||
# DATABASE_URL='postgresql://postgres:postgres@postgres:5432/formbricks?schema=public'
|
||||
|
||||
################
|
||||
# Mail Setup #
|
||||
################
|
||||
|
||||
# Necessary if email verification and password reset are enabled.
|
||||
# See optional configurations below if you want to disable these features.
|
||||
|
||||
MAIL_FROM=noreply@example.com
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=1025
|
||||
SMTP_SECURE_ENABLED=0 # Enable for TLS (port 465)
|
||||
SMTP_USER=smtpUser
|
||||
SMTP_PASSWORD=smtpPassword
|
||||
|
||||
|
||||
########################################################################
|
||||
# ------------------------------ OPTIONAL -----------------------------#
|
||||
########################################################################
|
||||
|
||||
# Uncomment the variables you would like to use and customize the values.
|
||||
|
||||
#####################
|
||||
# Disable Features #
|
||||
#####################
|
||||
|
||||
# Email Verification. If you enable Email Verification you have to setup SMTP-Settings, too.
|
||||
# NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED=1
|
||||
|
||||
# Password Reset. If you enable Password Reset functionality you have to setup SMTP-Settings, too.
|
||||
# NEXT_PUBLIC_PASSWORD_RESET_DISABLED=1
|
||||
|
||||
# Signup. Disable the ability for new users to create an account.
|
||||
# NEXT_PUBLIC_SIGNUP_DISABLED=1
|
||||
2
.gitignore
vendored
@@ -39,4 +39,4 @@ yarn-error.log*
|
||||
|
||||
# nixos stuff
|
||||
.direnv
|
||||
apps/examples
|
||||
apps/demo
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function WaitlistForm() {
|
||||
<Text name="firstname" label="What's your first name?" validation="required" />
|
||||
<Text name="lastname" label="What's your last name?" />
|
||||
<Textarea name="about" label="About you" help="Please keep it short" />
|
||||
<Submit label="Submit" />
|
||||
<Submit name="submit" label="Submit" />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,9 +40,9 @@ function Header({ navigation }: any) {
|
||||
return (
|
||||
<header
|
||||
className={clsx(
|
||||
"sticky top-0 z-50 flex flex-wrap items-center justify-between bg-white px-4 py-5 shadow-md shadow-slate-900/5 transition duration-500 dark:shadow-none sm:px-6 lg:px-8",
|
||||
"sticky top-0 z-50 flex flex-wrap items-center justify-between bg-slate-100 px-4 py-5 shadow-md shadow-slate-900/5 transition duration-500 dark:shadow-none sm:px-6 lg:px-8",
|
||||
isScrolled
|
||||
? "dark:bg-slate-900/95 dark:backdrop-blur dark:[@supports(backdrop-filter:blur(0))]:bg-slate-900/75"
|
||||
? "bg-slate-100/90 backdrop-blur dark:bg-slate-900/90 [@supports(backdrop-filter:blur(0))]:bg-slate-100/75 dark:[@supports(backdrop-filter:blur(0))]:bg-slate-900/75"
|
||||
: "dark:bg-transparent"
|
||||
)}>
|
||||
<div className="mr-6 flex lg:hidden">
|
||||
@@ -50,27 +50,24 @@ function Header({ navigation }: any) {
|
||||
</div>
|
||||
<div className="relative flex flex-grow basis-0 items-center">
|
||||
<Link href="/" aria-label="Home page">
|
||||
<Logomark className="h-9 w-9 lg:hidden" />
|
||||
<FooterLogo className="hidden h-9 w-auto fill-slate-700 dark:fill-slate-100 lg:block" />
|
||||
<FooterLogo className="h-8 w-auto sm:h-10" />
|
||||
</Link>
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => router.push("/")}
|
||||
size="sm"
|
||||
className="ml-10 hidden justify-center opacity-60 sm:flex">
|
||||
← Back to Mainpage
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-my-5 mr-6 sm:mr-8 md:mr-0">
|
||||
<Search />
|
||||
</div>
|
||||
<div className="relative flex basis-0 justify-end gap-6 sm:gap-8 md:flex-grow">
|
||||
<ThemeSelector className="relative z-10" />
|
||||
<Link href="https://github.com" className="group" aria-label="GitHub">
|
||||
<GitHubIcon className="h-6 w-6 fill-slate-400 group-hover:fill-slate-500 dark:group-hover:fill-slate-300" />
|
||||
</Link>
|
||||
<div className="hidden items-center justify-end md:flex md:flex-1 lg:w-0">
|
||||
<ThemeSelector className="relative z-10 mr-5" />
|
||||
<Button
|
||||
variant="secondary"
|
||||
EndIcon={GitHubIcon}
|
||||
endIconClassName="fill-slate-800 dark:fill-slate-200"
|
||||
onClick={() => router.push("https://github.com/formbricks/formbricks")}>
|
||||
View on Github
|
||||
</Button>
|
||||
<Button variant="highlight" className="ml-2" onClick={() => router.push("/get-started")}>
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
||||
194
apps/formbricks-com/components/shared/APILayout.tsx
Normal file
@@ -0,0 +1,194 @@
|
||||
import { useState, ChangeEvent } from "react";
|
||||
import { ChevronDownIcon, ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/20/solid";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface APICallProps {
|
||||
method: "GET" | "POST";
|
||||
url: string;
|
||||
description: string;
|
||||
queries: {
|
||||
label: string;
|
||||
type: string;
|
||||
description: string;
|
||||
}[];
|
||||
bodies: {
|
||||
label: string;
|
||||
type: string;
|
||||
description: string;
|
||||
required?: boolean;
|
||||
}[];
|
||||
responses: {
|
||||
color: string;
|
||||
statusCode: string;
|
||||
description: string;
|
||||
example?: string;
|
||||
}[];
|
||||
example?: string;
|
||||
}
|
||||
|
||||
export function APILayout({ method, url, description, queries, bodies, responses, example }: APICallProps) {
|
||||
const [switchState, setSwitchState] = useState(false);
|
||||
function handleOnChange() {
|
||||
setSwitchState(!switchState);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-lg bg-slate-200 p-8 dark:bg-slate-700">
|
||||
{switchState ? (
|
||||
<ChevronDownIcon
|
||||
className="hover:text-brand-dark dark:hover:text-brand-dark mr-3 inline h-5 w-5 hover:cursor-pointer"
|
||||
aria-hidden="true"
|
||||
onClick={handleOnChange}
|
||||
/>
|
||||
) : (
|
||||
<ChevronRightIcon
|
||||
className="hover:text-brand-dark dark:hover:text-brand-dark mr-3 inline h-5 w-5 hover:cursor-pointer"
|
||||
aria-hidden="true"
|
||||
onClick={handleOnChange}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={clsx(
|
||||
"mr-3 inline rounded-full p-1 px-3 font-semibold text-white",
|
||||
method === "POST" && "bg-red-400",
|
||||
method === "GET" && "bg-green-400"
|
||||
)}>
|
||||
{method}
|
||||
</div>
|
||||
<div className="inline text-sm text-slate-500">
|
||||
http://localhost:300/api
|
||||
<span className="font-bold text-black">{url}</span>
|
||||
</div>
|
||||
<div className="mt-4 ml-8 font-bold">{description}</div>
|
||||
<div>
|
||||
<div className={clsx(switchState ? "block" : "hidden", "ml-8")}>
|
||||
<p className="mt-6 mb-2 text-lg font-semibold">Parameters</p>
|
||||
<div>
|
||||
<div className="text-base">
|
||||
<p className="not-prose -mb-1 pt-2 font-bold">Query</p>
|
||||
<div>
|
||||
{queries.map((q) => (
|
||||
<Parameter key={q.label} label={q.label} type={q.type} description={q.description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 text-base">
|
||||
<p className="not-prose -mb-1 pt-2 font-bold">Body</p>
|
||||
<div>
|
||||
{}
|
||||
{bodies.map((b) => (
|
||||
<Parameter
|
||||
key={b.label}
|
||||
label={b.label}
|
||||
type={b.type}
|
||||
description={b.description}
|
||||
required={b.required}
|
||||
/>
|
||||
))}
|
||||
{example && (
|
||||
<div>
|
||||
<p className="not-prose mb-2 pt-2 font-bold">Body Example</p>
|
||||
<div className="rounded-lg bg-slate-300 p-2 font-mono text-sm">{example}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 text-base">
|
||||
<p className="not-prose -mb-1 pt-2 font-bold">Responses</p>
|
||||
<div>
|
||||
{responses.map((r) => (
|
||||
<Response
|
||||
key={r.color}
|
||||
color={r.color}
|
||||
statusCode={r.statusCode}
|
||||
description={r.description}
|
||||
example={r.example}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ParaProps {
|
||||
label: string;
|
||||
type: string;
|
||||
description: string;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
function Parameter({ label, type, description, required }: ParaProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="my-2 grid grid-cols-4 text-sm">
|
||||
<div className="inline font-mono">
|
||||
{label}
|
||||
{required && <p className="inline font-bold text-red-500">*</p>}
|
||||
</div>
|
||||
<div>{type}</div>
|
||||
<div className="col-span-2">{description}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface RespProps {
|
||||
color: string;
|
||||
statusCode: string;
|
||||
description: string;
|
||||
example?: string;
|
||||
}
|
||||
|
||||
function Response({ color, statusCode, description, example }: RespProps) {
|
||||
const [toggleExample, setSwitchState] = useState(false);
|
||||
function handleOnChange() {
|
||||
setSwitchState(!toggleExample);
|
||||
}
|
||||
return (
|
||||
<div className="my-2 grid grid-cols-2 text-sm">
|
||||
<div className="text-md inline-flex items-center font-semibold">
|
||||
<div
|
||||
className={clsx(
|
||||
"mr-3 inline h-3 w-3 rounded-full",
|
||||
color === "green" && "bg-green-400",
|
||||
color === "brown" && "bg-amber-800"
|
||||
)}>
|
||||
|
||||
</div>
|
||||
<div>{statusCode}</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>{description}</div>
|
||||
<div className="font-bold">
|
||||
{example &&
|
||||
(toggleExample ? (
|
||||
<ChevronDownIcon
|
||||
className={clsx(
|
||||
toggleExample ? "block" : "hidden",
|
||||
"hover:text-brand-dark dark:hover:text-brand-dark mr-3 inline h-6 w-6 hover:cursor-pointer"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
onClick={handleOnChange}
|
||||
/>
|
||||
) : (
|
||||
<ChevronLeftIcon
|
||||
className={clsx(
|
||||
toggleExample ? "hidden" : "block",
|
||||
"hover:text-brand-dark dark:hover:text-brand-dark mr-3 inline h-6 w-6 hover:cursor-pointer"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
onClick={handleOnChange}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{example && toggleExample && (
|
||||
<div className="col-span-2 my-3 rounded-lg bg-slate-300 p-2 font-mono">{example}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -449,7 +449,7 @@ export default function Header() {
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => router.push("https://app.formbricks.com")}
|
||||
onClick={() => router.push("/get-started")}
|
||||
className="mt-3 flex w-full justify-center">
|
||||
Get started
|
||||
</Button>
|
||||
|
||||
61
apps/formbricks-com/components/shared/NewsletterSignup.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import Image from "next/image";
|
||||
import Button from "@/components/shared/Button";
|
||||
import Friends from "@/images/newsletter-signup-gif.gif";
|
||||
|
||||
export default function WaitlistForm() {
|
||||
return (
|
||||
<div className="not-prose text-md mx-auto mt-12 max-w-7xl rounded-lg bg-slate-200 p-10 text-slate-500 shadow-lg dark:bg-slate-800 dark:text-slate-400">
|
||||
<p className="my-0 text-2xl font-bold text-slate-600 dark:text-slate-300">Build in public</p>
|
||||
Get all the juicy details of our journey building Formbricks in public 👇
|
||||
<div className="mt-8 gap-4 md:grid md:grid-cols-2">
|
||||
<form method="post" action="https://listmonk.formbricks.com/subscription/form">
|
||||
<div className="p-6 ">
|
||||
<div>
|
||||
<input type="hidden" name="nonce" />
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
required
|
||||
placeholder="Email"
|
||||
className="block w-full rounded-xl text-slate-900 shadow-sm focus:border-slate-500 focus:ring-slate-500 sm:text-sm"
|
||||
/>
|
||||
<label htmlFor="email" className="ml-2 block text-sm text-slate-400 dark:text-slate-500">
|
||||
Work or personal
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
required
|
||||
className="mt-4 block w-full rounded-xl text-slate-900 shadow-sm focus:border-slate-500 focus:ring-slate-500 sm:text-sm"
|
||||
/>
|
||||
<label htmlFor="name" className="ml-2 block text-sm text-slate-400 dark:text-slate-500">
|
||||
Optional but appreciated
|
||||
</label>
|
||||
</div>
|
||||
<div className="hidden">
|
||||
<input
|
||||
id="e0084"
|
||||
type="checkbox"
|
||||
name="l"
|
||||
checked
|
||||
value="e0084486-8751-43e4-8cfb-58b7c3f5f318"
|
||||
readOnly
|
||||
/>
|
||||
<label htmlFor="e0084">Build in public</label>
|
||||
</div>
|
||||
<Button type="submit" className="mt-5 w-full justify-center">
|
||||
Subscribe
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<Image src={Friends} alt="Sign up to newsletter" className="not-prose rounded-xl" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
BIN
apps/formbricks-com/images/newsletter-signup-gif.gif
Normal file
|
After Width: | Height: | Size: 461 KiB |
@@ -35,6 +35,26 @@ const navigation = [
|
||||
title: "Form Wrapper",
|
||||
href: "/docs/react-form-library/form-wrapper",
|
||||
},
|
||||
{
|
||||
title: "Input: Checkbox",
|
||||
href: "/docs/react-form-library/input-checkbox",
|
||||
},
|
||||
{
|
||||
title: "Input: Email",
|
||||
href: "/docs/react-form-library/input-email",
|
||||
},
|
||||
{
|
||||
title: "Input: Number",
|
||||
href: "/docs/react-form-library/input-number",
|
||||
},
|
||||
{
|
||||
title: "Input: Password",
|
||||
href: "/docs/react-form-library/input-password",
|
||||
},
|
||||
{
|
||||
title: "Input: Phone",
|
||||
href: "/docs/react-form-library/input-phone",
|
||||
},
|
||||
{
|
||||
title: "Input: Text",
|
||||
href: "/docs/react-form-library/input-text",
|
||||
@@ -47,10 +67,14 @@ const navigation = [
|
||||
title: "Input: Radio Button",
|
||||
href: "/docs/react-form-library/input-radio",
|
||||
},
|
||||
/* {
|
||||
title: "Input: Checkbox",
|
||||
href: "/docs/react-form-library/input-checkbox",
|
||||
}, */
|
||||
{
|
||||
title: "Input: URL",
|
||||
href: "/docs/react-form-library/input-url",
|
||||
},
|
||||
{
|
||||
title: "Input: Search",
|
||||
href: "/docs/react-form-library/input-search",
|
||||
},
|
||||
{
|
||||
title: "Input: Submit",
|
||||
href: "/docs/react-form-library/input-submit",
|
||||
@@ -63,20 +87,21 @@ const navigation = [
|
||||
title: "Style with Tailwind",
|
||||
href: "/docs/react-form-library/style-tailwind",
|
||||
},
|
||||
{
|
||||
title: "Icons",
|
||||
href: "/docs/react-form-library/icons",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Data Pipelines",
|
||||
title: "Formbricks HQ",
|
||||
links: [
|
||||
{ title: "Core API", href: "/docs/data-pipelines/core-api" },
|
||||
{ title: "Email Notifications", href: "/docs/data-pipelines/email-notifications" },
|
||||
{ title: "Webhooks", href: "/docs/data-pipelines/webhooks" },
|
||||
{ title: "Core API", href: "/docs/formbricks-hq/core-api" },
|
||||
{ title: "Schema", href: "/docs/formbricks-hq/schema" },
|
||||
{ title: "Email Notifications (UI)", href: "/docs/formbricks-hq/ui/email-notifications" },
|
||||
{ title: "Webhooks (UI)", href: "/docs/formbricks-hq/ui/webhooks" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Data Insights",
|
||||
links: [{ title: "Formbricks HQ", href: "/docs/data-insights/formbricks-hq" }],
|
||||
},
|
||||
];
|
||||
|
||||
export default navigation;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import Image from "next/image";
|
||||
import LayoutMdx from "@/components/shared/LayoutMdx";
|
||||
import LaunchDay from "./launch react library form builder survey with multi-step form open-source.png";
|
||||
import LaunchDay from "./launch2-react library form builder survey with multi-step form open-source.png";
|
||||
import MdxTryItCTA from "@/components/shared/MdxTryItCTA.tsx";
|
||||
import Styling from "../../docs/react-form-library/style-css/HTML classes of Formbricks React Form Library to custom style surveys and forms.png";
|
||||
import CodeExample from "./v2 developer experience best react library 2023 forms and surveys open source.png";
|
||||
|
||||
export const meta = {
|
||||
title: "React Form Library launched! 🚀",
|
||||
title: "React Form Library launched! 🚀 [Updated]",
|
||||
description: "We are pumped to announce that the Formbricks React Form Library is ready to be used!",
|
||||
date: "2022-11-22",
|
||||
date: "2022-11-24",
|
||||
};
|
||||
|
||||
<Image src={LaunchDay} alt="Robin Hood Meme" className="rounded-lg" />
|
||||
@@ -27,14 +27,24 @@ We want to make forms in React more accessible. To achieve that, we work with:
|
||||
|
||||
<Image src={CodeExample} alt="Robin Hood Meme" className="rounded-lg" />
|
||||
|
||||
### What does it come with?
|
||||
### What does it come with? [Updated]
|
||||
|
||||
In version 0.1 we layed the foundation for performant, easy to build forms. The library includes:
|
||||
|
||||
- Text Input
|
||||
- Textarea Input
|
||||
- Submit Button
|
||||
- Validation
|
||||
- Checkboxes
|
||||
- Radio Buttons
|
||||
- Phone Input
|
||||
- Email Input
|
||||
- URL Input
|
||||
- Password Input
|
||||
- Search Input
|
||||
- Submit Button with Icons
|
||||
|
||||
And additional features like
|
||||
|
||||
- Validation & Error Messages
|
||||
- Tailwind Support
|
||||
- Standard CSS Support
|
||||
|
||||
@@ -42,7 +52,6 @@ In version 0.1 we layed the foundation for performant, easy to build forms. The
|
||||
|
||||
### Whats on the roadmap?
|
||||
|
||||
- All HTML input types (checkbox, phone, email, address, etc)
|
||||
- Common non-HTML question types (Slider, star-rating, NPS, toggle, etc.)
|
||||
- Easy multi-step forms
|
||||
- Easy form logic
|
||||
|
||||
|
After Width: | Height: | Size: 80 KiB |
BIN
apps/formbricks-com/pages/blog/weekly-update-021222/chart-1.webp
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
apps/formbricks-com/pages/blog/weekly-update-021222/chart-2.webp
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
apps/formbricks-com/pages/blog/weekly-update-021222/chart-3.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 34 KiB |
166
apps/formbricks-com/pages/blog/weekly-update-021222/index.mdx
Normal file
@@ -0,0 +1,166 @@
|
||||
import Image from "next/image";
|
||||
import LayoutMdx from "@/components/shared/LayoutMdx";
|
||||
import HeaderImage from "../weekly-update-181122/weeklyupdate.png";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import NewsletterSignup from "@/components/shared/NewsletterSignup";
|
||||
|
||||
import Chart1 from "./chart-1.webp";
|
||||
import Chart2 from "./chart-2.webp";
|
||||
import Chart3 from "./chart-3.webp";
|
||||
import Results1 from "./results-1.webp";
|
||||
import Results2 from "./results-2.webp";
|
||||
import Crowd from "./crowd-dev-1.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Weekly Summary - 2nd Dec 2022",
|
||||
description:
|
||||
"And it is December! This week was dominated by working on the Formbricks HQ, Formbricks Charts and the YC interview. Let’s look at it in detail.",
|
||||
date: "2022-12-02",
|
||||
};
|
||||
|
||||
_And it is December! This week was dominated by working on the Formbricks HQ, Formbricks Charts and the YC interview. Let’s look at it in detail 👇_
|
||||
|
||||
<Image src={HeaderImage} alt="Weekly Update" className="rounded-lg" />
|
||||
|
||||
# Highlights
|
||||
|
||||
- Formbricks HQ almost ready 🚢
|
||||
- Formbricks Charts 📈
|
||||
- YC Interview 🍊
|
||||
|
||||
Let's dive in!
|
||||
|
||||
##
|
||||
|
||||
# Product
|
||||
|
||||
### Formbricks HQ (launching next week)
|
||||
|
||||
We made very good progress with the new Formbricks HQ. We rebuilt the use case of the Swiss government adding native feedback functionality into an existing app - super smooth!
|
||||
|
||||
<Callout title="Modular is the way" type="note">
|
||||
The Swiss pulled snoopForms apart to build their feedback feature. A few more early users did that which led
|
||||
us to build a modular set of tools: they work independently but are well integrated e.g. by the use of a
|
||||
shared data schema.
|
||||
</Callout>
|
||||
|
||||
Here is a quick run-through to show how our modular setup plays out:
|
||||
|
||||
### Step 1: Build the form with Formbricks React
|
||||
|
||||
Within a few minutes we spun up the right form. Look how easy radio buttons can be in React, styled with Tailwind CSS 😍
|
||||
|
||||
```tsx
|
||||
import { Form, Radio, Submit, sendToHq, Textarea } from "@formbricks/react";
|
||||
|
||||
...
|
||||
<Form formId="clb4yr1m90000XXXXXXXX" hqUrl="http://localhost:3000" onSubmit={sendToHq}>
|
||||
<Radio
|
||||
name="evaluate"
|
||||
label="Evaluate the online course you just completed"
|
||||
legendClassName="mb-3 font-bold text-gray-800 text-xl"
|
||||
labelClassName="font-regular text-gray-500 text-lg"
|
||||
options={["Perfect", "Very satisfactory", "Satisfactory", "Not very satisfactory", "Useless"]}
|
||||
/>
|
||||
<Textarea
|
||||
name="feedback"
|
||||
label="Would you like to send us a comment, an opinion, a correction?"
|
||||
help="Only you and us can see your answer."
|
||||
labelClassName="font-bold text-gray-800 text-xl"
|
||||
innerClassName="mt-3"
|
||||
cols={50}
|
||||
rows={4}
|
||||
/>
|
||||
<Submit
|
||||
label="Answer"
|
||||
inputClassName="flex items-center justify-center rounded-md border border-transparent
|
||||
bg-gradient-to-r from-purple-600 to-indigo-600 bg-origin-border px-3 py-2 text-base
|
||||
font-medium text-white shadow-sm hover:from-purple-700 hover:to-indigo-700"
|
||||
/>
|
||||
</Form>
|
||||
```
|
||||
|
||||
<Image src={Chart1} alt="Weekly Update Demo Custom Native Feedback Function" className="rounded-lg" />
|
||||
|
||||
### Step 2: Pipe it up with Formbricks HQ
|
||||
|
||||
We hooked it up with the Formbricks HQ to store the data. The React Lib sends a data schema along with the submission to assure a complete picture of the data. Read more about schemas in our [docs](/docs/formbricks-hq/schema):
|
||||
|
||||
```tsx
|
||||
<Form
|
||||
formId="clb4yr1m90000yzaXXXXXXXX"
|
||||
hqUrl="http://localhost:3000"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
```
|
||||
|
||||
<Image src={Results1} alt="Weekly Update Demo Custom Native Feedback Function" className="rounded-lg" />
|
||||
|
||||
### Step 3: Display the results right after submission
|
||||
|
||||
They were looking for a polling functionality so showing the enduser the results right after they submitted their answer. We built Formbricks Charts to enable that with a single line of code:
|
||||
|
||||
```tsx
|
||||
import { Bar } from "@formbricks/charts";
|
||||
|
||||
...
|
||||
|
||||
<h2 className="mx-auto mb-3 text-lg font-bold text-gray-800">
|
||||
Thanks a lot for your feedback
|
||||
</h2>
|
||||
<p className="mb-5 text-lg text-gray-500">
|
||||
Here you can see what other people answered.
|
||||
</p>
|
||||
|
||||
/* Visualize Submission using Formbricks Charts Library */
|
||||
<Bar
|
||||
submissions="{submissions}"
|
||||
schema="{schema}"
|
||||
fieldName="evaluate"
|
||||
color="#4f46e5"
|
||||
/>
|
||||
```
|
||||
|
||||
<Image src={Chart3} alt="Weekly Update Demo Custom Native Feedback Function" className="rounded-lg" />
|
||||
|
||||
### Formbricks Charts
|
||||
|
||||
Formbricks charts is a package to display form data collected with Formbricks React or the upcoming Visual Form Builder. It’s leveraging the great [Recharts](https://recharts.org) package.
|
||||
|
||||
With a single line of code you can display your form data wherever you need it:
|
||||
|
||||
```tsx
|
||||
<Bar submissions={submissions} schema={schema} fieldName="fieldToVisualize" />
|
||||
|
||||
/* or */
|
||||
|
||||
<Table submissions={submissions} schema={schema} fieldName="fieldToVisualize" />
|
||||
```
|
||||
|
||||
We also use the same package to display our charts in Formbricks HQ:
|
||||
|
||||
<Image src={Results2} alt="Formbricks HQ Demo Custom Native Feedback with Charts" className="rounded-lg" />
|
||||
|
||||
# Community
|
||||
|
||||
We had a few great in-depth chats with builders looking to use Formbricks. Special shout out to jetsoms, LD and kiran for sharing so much about their pain points with other solutions.
|
||||
|
||||
Here is a little overview of our crowds activity on GitHub and Discord over the past week:
|
||||
|
||||
<Image src={Crowd} alt="Weekly Update Demo Custom Native Feedback Function" className="rounded-lg" />
|
||||
|
||||
## YC Interview
|
||||
|
||||
Last night we had our YC interview.
|
||||
|
||||
Our experience was surprisingly relaxed, Nicolas just tried to understand what we’re building, why and what we have learned about our users over the past couple of months.
|
||||
|
||||
We talked about how we see Formbricks develop from solving form infrastructure to becoming an open source alternative to Qualitrcs, what happened with snoopForms and more.
|
||||
|
||||
Some say you hear from YC within a few hours in case they want to invest. On the website it says they'll get back to us within a day or two - let's see how it shakes out.
|
||||
|
||||
Generally, it was super exciting to be invited and look at what we have done and are planning to do through the YC lens 🚀 We got a lot more pumped about size of the opportunity ahead of us!
|
||||
|
||||
<NewsletterSignup />
|
||||
|
||||
export default ({ children }) => <LayoutMdx meta={meta}>{children}</LayoutMdx>;
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -1,11 +1,11 @@
|
||||
import Image from "next/image";
|
||||
import LayoutMdx from "@/components/shared/LayoutMdx";
|
||||
import Button from "@/components/shared/Button";
|
||||
import Mockup from "./demo mockup for formbricks hq open source form and survey tool.png";
|
||||
import NewLogo from "./formbricks new logo mockup community feedback.png";
|
||||
import Community from "./community feedback logo and name.png";
|
||||
import Storybook from "./storybook for formbricks survey form builder.png";
|
||||
import HeaderImage from "./weeklyupdate.png";
|
||||
import NewsletterSignup from "@/components/shared/NewsletterSignup";
|
||||
|
||||
export const meta = {
|
||||
title: "Weekly Summary - 18th Nov 2022",
|
||||
@@ -91,42 +91,6 @@ Let’s hope Elon doesn’t break it too soon.
|
||||
|
||||
## Have a great weekend!
|
||||
|
||||
---
|
||||
|
||||
<div className="mx-auto max-w-7xl px-5 py-5 bg-white shadow-lg rounded-lg text-md text-gray-700">
|
||||
|
||||
You would like to have Formbricks "Build in Public Updates" like this in your mailbox? Subscribe to our
|
||||
newsletter 💪
|
||||
|
||||
<form method="post" action="https://listmonk.formbricks.com/subscription/form" className="listmonk-form">
|
||||
<div>
|
||||
<input type="hidden" name="nonce" />
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
Email
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input type="email" name="email" required placeholder="you@example.com" className="block w-full rounded-md border-gray-300 shadow-sm focus:border-slate-500 focus:ring-slate-500 sm:text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||||
Name (optional)
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input type="text" name="name" required className="block w-full rounded-md border-gray-300 shadow-sm focus:border-slate-500 focus:ring-slate-500 sm:text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='hidden'>
|
||||
<input id="e0084" type="checkbox" name="l" checked value="e0084486-8751-43e4-8cfb-58b7c3f5f318" readOnly />
|
||||
<label htmlFor="e0084">Build in public</label>
|
||||
</div>
|
||||
|
||||
<Button type="submit" className="mt-4 w-full justify-center">Subscribe</Button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<NewsletterSignup />
|
||||
|
||||
export default ({ children }) => <LayoutMdx meta={meta}>{children}</LayoutMdx>;
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 49 KiB |
111
apps/formbricks-com/pages/blog/weekly-update-251122/index.mdx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Image from "next/image";
|
||||
import LayoutMdx from "@/components/shared/LayoutMdx";
|
||||
import NewsletterSignup from "@/components/shared/NewsletterSignup";
|
||||
import HeroAnimation from "@/components/shared/HeroAnimation";
|
||||
import HeaderImage from "./weeklyupdate.png";
|
||||
import POC from "./proof-of-concept.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Weekly Summary - 25th Nov 2022",
|
||||
description:
|
||||
"Every week, we’ll share an update about all things Formbricks. This week we shipped, wrote docs, talked about a feedback app built on top of snoopForms and prepped for the YC interview! 👉",
|
||||
date: "2022-11-25",
|
||||
};
|
||||
|
||||
_This week we shipped Formbricks React v0.1 and v0.2, wrote lots of docs, talked about a feedback app built on top of snoopForms and prepped for the upcoming YC interview! 🤸_
|
||||
|
||||
<Image src={HeaderImage} alt="Weekly Update" className="rounded-lg" />
|
||||
|
||||
# Highlights
|
||||
|
||||
- shipped Formbricks React 🚢
|
||||
- met devs who built a feedback solution with snoopForms 🦝
|
||||
- got invited to YC interview 🍊
|
||||
|
||||
Let's dive in!
|
||||
|
||||
##
|
||||
|
||||
# Product
|
||||
|
||||
### Launched Formbricks React Library 🥳
|
||||
|
||||
We launched v0.1 and v0.2 of the Formbricks React Library.
|
||||
|
||||
- **Why?** Make it as easy as possible to build forms in React
|
||||
- **How?** Offering all essential form functionality out of the box
|
||||
- **What?** Lots of input components, validation, easy styling, easy multi-step forms, i18n, a11y and everything else you need when building forms in React.
|
||||
|
||||
Have a look at this example:
|
||||
|
||||
```jsx
|
||||
import { Form, Text, Email, Checkbox, Submit } from "@formbricks/react";
|
||||
import "@formbricks/react/styles.css";
|
||||
|
||||
export default function WaitlistForm() {
|
||||
return (
|
||||
<Form onSubmit={({ data, schema }) => console.log("data:", data, "schema:", schema)}>
|
||||
<Text name="name" label="What's your name?" validation="required" />
|
||||
<Email
|
||||
name="email"
|
||||
label="What's your email address?"
|
||||
placeholder="you@example.com"
|
||||
validation="required|email"
|
||||
/>
|
||||
<Checkbox
|
||||
name="terms"
|
||||
label="Terms & Conditions"
|
||||
help="To use our service, please accept."
|
||||
validation="accepted"
|
||||
/>
|
||||
<Submit label="Let's go!" />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
A lot more information in the [Docs, check them out!](/docs/react-form-library/introduction)
|
||||
|
||||
### What's next for Formbricks React?
|
||||
|
||||
In the upcoming week we're not planning to add more features to it. We'll first ship a version of the Formbricks HQ to offer an end-to-end solution from form creation to submission handling to analysis 👇
|
||||
|
||||
## Formbricks HQ Demo
|
||||
|
||||
With the YC interview coming up next week, we decided to build an end-to-end demo. We're not focussing on production readiness for now. Expect to get your fingers on it the week after!
|
||||
|
||||
<HeroAnimation />
|
||||
|
||||
## Feedback tool for the State of Geneva, Switzerland
|
||||
|
||||
We were delighted to find out that a digital agency built a POC for a feedback functionality in an e-learning offer from the state of Geneva, Switzerland.
|
||||
|
||||
In the call we learned a lot about why they chose snoopForms (privacy-first), how their developer experience has been (pretty good) and what they need in the future.
|
||||
|
||||
They are working on a more comprehensive offer for forms & surveys for the Swiss market built on top of Formbricks!
|
||||
|
||||
So exciting for us to see that our product and positioning resonates so well 😊
|
||||
|
||||
<Image src={POC} alt="SCreenshot from feedback tool built with snoopforms" className="rounded-lg" />
|
||||
|
||||
##
|
||||
|
||||
# Community
|
||||
|
||||
Shoutout to octalpixel and [Akshu](https://twitter.com/Akshu_on_github) from the EddieHub community for sharing feedback on the React Library. Highly appreciated 🙏
|
||||
|
||||
## Listmonk
|
||||
|
||||
We chose [Listmonk](https://listmonk.app/) as our Newsletter tool as it is a promising open-source option. So far the setup has been pretty good!
|
||||
|
||||
You can sign up to our "Build in Public" list at the bottom of this article to not miss a single one of them 😉
|
||||
|
||||
## YC Interview
|
||||
|
||||
We got invited! This is obviously very exciting so we spent some time getting our answers crisp. We're talking some alumns to learn from their experience 🤞
|
||||
|
||||
## Have a great weekend!
|
||||
|
||||
<NewsletterSignup />
|
||||
|
||||
export default ({ children }) => <LayoutMdx meta={meta}>{children}</LayoutMdx>;
|
||||
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 53 KiB |
@@ -1,10 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "Formbricks HQ",
|
||||
};
|
||||
|
||||
coming soon
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "Core API",
|
||||
};
|
||||
|
||||
coming soon
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "Email Notifications",
|
||||
};
|
||||
|
||||
coming soon
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "Webhooks",
|
||||
};
|
||||
|
||||
coming soon
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 62 KiB |
189
apps/formbricks-com/pages/docs/formbricks-hq/core-api/index.mdx
Normal file
@@ -0,0 +1,189 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import Image from "next/image";
|
||||
import Architecture from "./api-endpoints.png";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "Core API - Formbricks Open Source Form & Survey Builder",
|
||||
};
|
||||
|
||||
## Why a form API?
|
||||
|
||||
We want to empower you to rapidly build exactly the form and survey functionality that you need. An open API is key to achieve that as it gives you access to every single data model within the application. This allows you to replicate the entire functionality of [Formbricks HQ](/formbricks-hq) in your own app using the API.
|
||||
|
||||
## Architecture
|
||||
|
||||
Especially large organisations with multiple teams suffer from scatterd qualitative data. This is why we baked in scaleability right from the start. The data models are structured as follows:
|
||||
|
||||
<Image src={Architecture} alt="Data model of open source form tool" className="rounded-lg" />
|
||||
|
||||
## Auth: Personal API key
|
||||
|
||||
The API requests are authorized with a personal API key. This API key gives you the same rights as if you were logged in at formbricks.com - **don't share it around!**
|
||||
|
||||
### How to generate an API key
|
||||
|
||||
1. Go to your profile at [hq.formbricks.com](https://hq.formbricks.com/app/me/settings).
|
||||
2. Select “Add key”.
|
||||
3. Assign it any label (this is just for you).
|
||||
4. Copy the key. You won’t be able to see it again.
|
||||
|
||||
<Callout title="Store API key safely" type="warning">
|
||||
Anyone who has your API key has full control over your account. For security reasons, you cannot view the
|
||||
API key again.
|
||||
</Callout>
|
||||
|
||||
### Delete a personal API key
|
||||
|
||||
1. Go to your profile at [hq.formbricks.com](https://hq.formbricks.com/app/me/settings).
|
||||
2. Find the key you wish to revoke and select “Delete”.
|
||||
3. Your API key will stop working immediately.
|
||||
|
||||
## User
|
||||
|
||||
### Find current user
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/users/me"
|
||||
description="Get the current logged in user."
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
]}
|
||||
responses={[
|
||||
{ color: "green", statusCode: "tba", description: "tba" },
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
## Team
|
||||
|
||||
### Find memberships
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/memberships"
|
||||
description="Get all of my team memberships."
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
]}
|
||||
responses={[
|
||||
{ color: "green", statusCode: "tba", description: "tba" },
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
### Get specific team
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/teams/[teamId]"
|
||||
description="Get a specific team by team ID."
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
]}
|
||||
responses={[
|
||||
{ color: "green", statusCode: "tba", description: "tba" },
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
## Forms
|
||||
|
||||
### Get all forms of a team
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/teams/[teamId]/forms"
|
||||
description="Get all forms of a team by team ID."
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
]}
|
||||
responses={[
|
||||
{ color: "green", statusCode: "tba", description: "tba" },
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
### Create new form
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/teams/[teamId]/forms"
|
||||
description="Create a new form"
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{ label: "label", type: "string", description: "The name you want to give your form.", required: true },
|
||||
{
|
||||
label: "schema",
|
||||
type: "JSON",
|
||||
description: "A valid Formbricks schema to provide provide context for the form data.",
|
||||
},
|
||||
]}
|
||||
responses={[
|
||||
{ color: "green", statusCode: "tba", description: "tba" },
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
## Submissions
|
||||
|
||||
### Get all submission of a form
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/teams/[teamId]/forms/[formId]/submissions"
|
||||
description="Request all submissions of a form by ID."
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
{ label: "tba", type: "tba", description: "tba" },
|
||||
]}
|
||||
responses={[
|
||||
{ color: "green", statusCode: "tba", description: "tba" },
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
### Create new submission
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/capture/forms/[formId]/submissions"
|
||||
description="Add a new submission to a form by form ID."
|
||||
queries={[{ label: "apiKey", type: "string", description: "Your API key" }]}
|
||||
bodies={[
|
||||
{
|
||||
label: "customerId",
|
||||
type: "string",
|
||||
description: "The customer/user you want to link the submission to.",
|
||||
},
|
||||
{
|
||||
label: "data",
|
||||
type: "JSON",
|
||||
description: "The content of the submission.",
|
||||
},
|
||||
]}
|
||||
example="hello"
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "tba",
|
||||
example: "{ // Response }",
|
||||
},
|
||||
{ color: "brown", statusCode: "tba", description: "tba" },
|
||||
]}
|
||||
/>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 53 KiB |
@@ -0,0 +1,99 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import Schema from "./data-visualisation-open-source-survey-builder.png";
|
||||
import NoSchema from "./no-schema-visualisation-of-open-source-data-form-builder-creator-webform.png";
|
||||
import Question from "./schema-open-source-form-creator-web-form-builder.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Schema – Open-source forms & survey infrastructure",
|
||||
};
|
||||
|
||||
## What is a schema?
|
||||
|
||||
A schema is like a manual for a form: It provides the context of the form including the questions, all answer options, information about pages and more. Essentially, it is the skeleton of your form stored in a .JSON file.
|
||||
|
||||
## Why are schemas helpful?
|
||||
|
||||
A schema is essential to get a full picture of the data you are collecting. Here is a simple example. Let’s say you have a form with one question like this:
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<Image
|
||||
className=""
|
||||
src={Question}
|
||||
alt="Open Source Form with Question about favorite food"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
<div className="mt-2">
|
||||
```json
|
||||
<Radio
|
||||
name="fav-food"
|
||||
label="What's your favorite food?"
|
||||
help="Allday, every day!"
|
||||
options={["Sushi", "Pasta", "Pizza"]}
|
||||
/>
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
|
||||
If you POST only the data to an API endpoint, it looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"submission": {
|
||||
"fav-food": "Pasta"
|
||||
},
|
||||
```
|
||||
|
||||
If you POST the data along with the schema, it looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"submission": {
|
||||
"fav-food": "pasta"
|
||||
},
|
||||
"schema": {
|
||||
"type": "form",
|
||||
"config": {},
|
||||
"children": [
|
||||
{
|
||||
"type": "radio",
|
||||
"name": "fav-food",
|
||||
"label": "What's your favorite food?",
|
||||
"options": ["Sushi", "Pasta", "Pizza"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Without the schema, a visualisation of your data looks like this:
|
||||
|
||||
<Image src={NoSchema} alt="Open Source Form with Question about favorite food" className="rounded-lg" />
|
||||
|
||||
As you can see, the question and answer options which were not selected are missing. Over time, when more submissions with different values come in, the visualisation will get more complete. However, when respondents can skip this question it will be challenging to make correct statements about this data point.
|
||||
|
||||
<Callout title="Inconsistent data" type="warning">
|
||||
The lack of a schema almost always leads to **inconsistent data.**
|
||||
</Callout>
|
||||
|
||||
With the schema, the visualisation looks like this:
|
||||
|
||||
<Image src={Schema} alt="Open Source Form with Question about favorite food" className="rounded-lg" />
|
||||
|
||||
As you can clearly see, this visualisation keeps track of all answer options as well as the initial question. The quality of your decisions will improve, especially over the course of several surveys.
|
||||
|
||||
### Why does it work on Typeform, Jotform, etc.?
|
||||
|
||||
If you are using standalone form builder like Typeform, Jotform or Tally they handle the schema internally. When you custom build your form functionality or use a Backend-as-a-Service provider like Formspree you should deal with schemas to get a full picture of your data. Or let us do it 👇
|
||||
|
||||
### Formbricks React 🤝 Formbricks HQ
|
||||
|
||||
Our React Form Library auto-generates a schema out of the form you have built. On submit it sends it over to the Formbricks HQ along with the submission data. Formbricks HQ understands the schema and can display your data correctly.
|
||||
|
||||
<Callout title="Forms how they should be" type="note">
|
||||
With Formbricks you get the level of integration of a custom-coded solution with the speed and ease of a
|
||||
SaaS tool 🤍
|
||||
</Callout>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,56 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import Image from "next/image";
|
||||
import Step1 from "./step-1-send-web-form-to-email-open-source.png";
|
||||
import Step2 from "./step-2-select-email-survey-response-to-email-send.png";
|
||||
import Step3 from "./step-3-add-email-to-send-form-data-to-open-source-alternative.png";
|
||||
import Step4 from "./step-4-set-active-to-send-survey-data-via-mail-to-myself-open-source.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Email Notifications (UI) - Open-source Forms & Surveys",
|
||||
};
|
||||
|
||||
You can send your form and survey data to your email address. To do so you can setup an Email Pipeline in your form settings.
|
||||
|
||||
## Send form data to email
|
||||
|
||||
### Setup
|
||||
|
||||
You need to have a form created to add a data pipeline to it.
|
||||
|
||||
### Step 1: Add Pipeline
|
||||
|
||||
In the top bar, select “Pipelines”. Click on “Add Pipeline” in the top right corner:
|
||||
|
||||
<Image src={Step1} className="rounded-lg" alt="Step 1 of sending form data to your email address" />
|
||||
|
||||
### Step 2: Select type of Pipeline
|
||||
|
||||
Select Email Notification. You can also set up a custom [Webhook](/docs/formbricks-hq/ui/webhooks).
|
||||
|
||||
<Image src={Step2} className="rounded-lg" alt="Step 2 of best webform to email tool" />
|
||||
|
||||
### Step 3: Configure settings
|
||||
|
||||
To setup your Pipeline you need to fill out two fields:
|
||||
|
||||
**Pipeline label:** Give it a name, this is just for you
|
||||
|
||||
**Email address:** Type in your email address
|
||||
|
||||
Then select “Create”.
|
||||
|
||||
<Image src={Step3} className="rounded-lg" alt="Step 3 of how to send form to email" />
|
||||
|
||||
### Step 4: Make sure it’s active
|
||||
|
||||
Congrats, you have created your email pipeline! Make sure it is set to “**Active**”.
|
||||
|
||||
<Image
|
||||
src={Step4}
|
||||
className="rounded-lg"
|
||||
alt="Step 4 of sending survey data form open source survey to your email"
|
||||
/>
|
||||
|
||||
From now on you will receive an email with the form content whenever someone submits your form. To deactive it, just turn it off. You can also delete it anytime.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,60 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import Image from "next/image";
|
||||
import Step1 from "../email-notifications/step-1-send-web-form-to-email-open-source.png";
|
||||
import Step2 from "../email-notifications/step-2-select-email-survey-response-to-email-send.png";
|
||||
import Step3 from "./step-3-send-form-data-webhook-open-source.png";
|
||||
import Step4 from "./step-4-webhook-survey-data-opensource.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Webhooks (UI) - Open source Forms & Surveys",
|
||||
};
|
||||
|
||||
You can send your form and survey data to a destination of your choice via a Webhook. To do so you can set up a Webhook Pipeline in your form settings.
|
||||
|
||||
## Send form data with Webhook
|
||||
|
||||
### Setup
|
||||
|
||||
You need to have a form created to add a data pipeline to it.
|
||||
|
||||
### Step 1: Add Pipeline
|
||||
|
||||
In the top bar, select “Pipelines”. Click on “Add Pipeline” in the top right corner:
|
||||
|
||||
<Image src={Step1} className="rounded-lg" alt="Step 1 of sending form data to your email address" />
|
||||
|
||||
### Step 2: Select type of Pipeline
|
||||
|
||||
Select Webhook. You can also set up an [Email Notification](/docs/formbricks-hq/ui/email-notifications).
|
||||
|
||||
<Image src={Step2} className="rounded-lg" alt="Step 2 of best webform to email tool" />
|
||||
|
||||
### Step 3: Configure settings
|
||||
|
||||
To setup your Webhook you need to fill out three fields:
|
||||
|
||||
**Webhook label:** Give it a name to know what this is for.
|
||||
|
||||
**Endpoint URL:** Copy your endpoint URL here. This is where the webhook sends the form data to.
|
||||
|
||||
**Secret**: To authenticate the data transmission, add a secret. You can generate one [here](https://www.lastpass.com/features/password-generator) or just type something in.
|
||||
|
||||
<Image src={Step3} className="rounded-lg" alt="Step 3 of how to send form to email" />
|
||||
Then select “Create”.
|
||||
|
||||
### Step 4: Make sure it’s active
|
||||
|
||||
Congrats, you have created your webhook pipeline! Make sure it is set to “**Active**”.
|
||||
|
||||
<Image
|
||||
src={Step4}
|
||||
className="rounded-lg"
|
||||
alt="Step 4 of sending survey data form open source survey to your email"
|
||||
/>
|
||||
|
||||
From now on the webhook will be triggered whenever someone submits your form. All form data will be sent to the
|
||||
destination.
|
||||
|
||||
To deactive it, just turn it off. You can also delete it anytime.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
@@ -9,7 +9,7 @@ The goal is clear: Build the last form tool humanity needs. What does such a sol
|
||||
|
||||
### Modular
|
||||
|
||||
Form needs differ widely but a one-size-fits all monolyth would fit no one. It would be slow and bloated. Only when it's possible to compose exactly the solution you need with the performance you expect we can compete with current solutions.
|
||||
Form needs differ widely but a one-size-fits all monolith would fit no one. It would be slow and bloated. Only when it's possible to compose exactly the solution you need with the performance you expect we can compete with current solutions.
|
||||
|
||||
### Customizable
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ export default function WaitlistForm() {
|
||||
<Text name="firstname" label="What's your first name?" validation="required" />
|
||||
<Text name="lastname" label="What's your last name?" />
|
||||
<Textarea name="about" label="About you" help="Please keep it short" />
|
||||
<Submit label="Submit" />
|
||||
<Submit name="submit" label="Submit" />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,74 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import FindIcon from "./icon-name-react-library-form-builder.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Icons - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
Icons give forms and surveys not only a professional look & feel, they increase the usability. Formbricks React supports icons in several locations throughout the form.
|
||||
|
||||
### Choosing an icon library
|
||||
|
||||
In the first step you have to decide which library you like. We like:
|
||||
|
||||
- [HeroIcons](https://heroicons.com/),
|
||||
- [FeatherIcons](https://feathericons.com/) (beautiful but limited),
|
||||
- [React Icons](https://react-icons.github.io/react-icons/). (huge collection)
|
||||
|
||||
### Installing library package
|
||||
|
||||
Once you picked yours you have to add it to your repository, e.g. HeroIcons:
|
||||
|
||||
```jsx
|
||||
npm install @heroicons/react
|
||||
```
|
||||
|
||||
### Importing icons
|
||||
|
||||
Next you have to import the icons you want to use them in your form:
|
||||
|
||||
```jsx
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
# or several at once
|
||||
|
||||
import { ChatBubbleOvalLeftEllipsisIcon, EnvelopeIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
```
|
||||
|
||||
If you paid close attention you noticed that we imported `PlusIcon` from the `outline` folder and the latter two from the `solid` folder. You can find the name of the icon you'd like to import on the respective website:
|
||||
|
||||
<Image
|
||||
src={FindIcon}
|
||||
alt="Illustration of error message and validation handling in best form react lib"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
Now you're ready to use them!
|
||||
|
||||
### Using icons
|
||||
|
||||
At this early stage, we only support icons in the submit button. You add it **before** and **after** the button text.
|
||||
|
||||
Before the button text:
|
||||
|
||||
```jsx
|
||||
<Submit label="Submit" PrefixIcon={EnvelopeIcon} />
|
||||
```
|
||||
|
||||
After the button text:
|
||||
|
||||
```jsx
|
||||
<Submit label="Submit" SuffixIcon={PlusIcon} />
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ---------- | ---- | ------- | --------------------------- |
|
||||
| PrefixIcon | SVG | - | Icon displayed before label |
|
||||
| SuffixIcon | SVG | - | Icon displayed after label |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,154 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./Checkbox-input-form-survey-react-lib-easy-build-forms-fast-validation-multi-step.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Checkbox - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The checkbox input uses [HTML's checkbox input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox) and can display one or many options to a user. It's a great way to allow users to select multiple items from a list. Formbricks supports single and multiple checkboxes.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<Checkbox name="terms" />
|
||||
```
|
||||
|
||||
## Single Checkbox
|
||||
|
||||
By default the checkbox input will render a single checkbox returning a `boolean` value:
|
||||
|
||||
```jsx
|
||||
<Checkbox
|
||||
name="newsletter"
|
||||
label="Monthly Newsletter"
|
||||
help="Would you like to receive our newsletter?"
|
||||
validation="accepted"
|
||||
/>
|
||||
```
|
||||
|
||||
## Multiple checkboxes
|
||||
|
||||
There are two ways to add several options to your checkbox input, both using the `options` attribute.
|
||||
|
||||
### Options: Array of values
|
||||
|
||||
The options attribute can handle an array of values which are interpreted both as label and value.
|
||||
|
||||
```jsx
|
||||
<Checkbox
|
||||
name="toppings"
|
||||
label="What do you like on your Pizza?"
|
||||
help="Take what you like"
|
||||
options={["Pineapple", "Ananas", "Piña"]}
|
||||
/>
|
||||
```
|
||||
|
||||
### Options: Array of objects
|
||||
|
||||
The options attribute can also handle an array of objects containing label/value pairs. This allows for differences between the label and the data stored. You can also add an optional config object:
|
||||
|
||||
```jsx
|
||||
<Checkbox
|
||||
name="allergies"
|
||||
label="What are you allergic to?"
|
||||
help="Tick all the boxes."
|
||||
options={[
|
||||
{
|
||||
label: "Dogs",
|
||||
value: "dogs",
|
||||
config: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "These nuts",
|
||||
value: "nuts",
|
||||
},
|
||||
{
|
||||
label: "Bullshit",
|
||||
value: "bs",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
## Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description | |
|
||||
| ---------------- | -------------------- | ------- | ------------------------------------------- | ---------------------------------------------------- |
|
||||
| options | Array | - | Contains the options in your checkbox input | |
|
||||
| label | String | - | The label of the checkbox input. | |
|
||||
| legendClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| optionsClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| optionClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-legend | The legend (often a question) |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-options | A wrapper around all options. |
|
||||
| formbricks-option | A wrapper around each option. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself, here the checkbox button. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<Checkbox
|
||||
name="toppings"
|
||||
label="What do you like on your Pizza?"
|
||||
help="Take what you like"
|
||||
options={["Pineapple", "Ananas", "Piña"]}
|
||||
legendClassName="font-bold"
|
||||
optionClassName="bg-gray rounded-sm"
|
||||
/>
|
||||
```
|
||||
|
||||
### Options-specific props to style it
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ---------------- | -------------------- | --------- | -------------------- | ---------------------------------------------------- |
|
||||
| legendClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| optionsClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| optionClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,79 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "../style-css/html-classes-of-formbricks-react-form-library-to-custom-style-surveys-and-forms.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Email Input - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The `Email` input uses HTML's [native email input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email). It allows a user to enter an email.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<Email name="email" />
|
||||
```
|
||||
|
||||
In most cases, it looks something like this:
|
||||
|
||||
```jsx
|
||||
<Email name="email" label="What's your email?" placeholder="Email" />
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ------------------------------------------------ |
|
||||
| placeholder | String | - | Placeholder before respondent clicks into field. |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your email field with adding CSS to the section classes. This is how the classes are named:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<Email name="email" label="What's your email?" inputClassName="bg-gray-800 my-5" />
|
||||
```
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,90 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./Number-input-best-easy-react-form-library-2023-forms-survey.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Number Input - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The `Number` input uses HTML's [native number input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number). It allows a user to enter a single integer or decimal value.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<Number name="age" />
|
||||
```
|
||||
|
||||
In most cases, it looks something like this:
|
||||
|
||||
```jsx
|
||||
<Number name="age" label="How old are you?" placeholder="42" min="1" max="130" step="1" />
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ------------------------------------------------------------------------------------ |
|
||||
| min | Number | - | The input has to be at least X |
|
||||
| max | Number | - | The input cannot be higher than Y |
|
||||
| step | Number | auto | Specifies the granularity that the value must adhere to when increasing / decreasing |
|
||||
| placeholder | String | - | Placeholder before respondent clicks into field. |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your number field with adding CSS to the section classes. This is how the classes are named:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<Number
|
||||
name="age"
|
||||
label="How old are you?"
|
||||
placeholder="42"
|
||||
min="1"
|
||||
max="130"
|
||||
step="1"
|
||||
inputClassName="font-bold"
|
||||
/>
|
||||
```
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,87 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./Password-input-easy-react-form-library-build-forms-surveys-fast.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Password Input - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The `Password` input uses HTML's [native password input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/password). It allows a user to enter a password.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<Password name="password" />
|
||||
```
|
||||
|
||||
In most cases, it looks something like this:
|
||||
|
||||
```jsx
|
||||
<Password
|
||||
name="password"
|
||||
label="Password"
|
||||
help="Enter secure password"
|
||||
placeholder="ilikecoldcoffee"
|
||||
validation="required"
|
||||
/>
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ------------------------------------------------ |
|
||||
| minLength | Number | 0 | Limits min length accepted in the field |
|
||||
| maxLength | Number | 524288 | Limits max length accepted in the field |
|
||||
| placeholder | String | - | Placeholder before respondent clicks into field. |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<Password name="password" label="Password" validation="required" outerClassName="bg-gray-800" />
|
||||
```
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,81 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./Phone-react-library-for-surveys-and-form-build-fast-and-easy.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Phone Input - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The `Phone` input uses HTML's [native tel input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/tel). It allows a user to enter a telephone number.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<Phone name="phone" />
|
||||
```
|
||||
|
||||
In most cases, it looks something like this:
|
||||
|
||||
```jsx
|
||||
<Phone name="phone" label="Phone" help="Enter your phone number." placeholder="+1 123 444 567" />
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ------------------------------------------------ |
|
||||
| minLength | Number | 0 | Limits min length accepted in the field |
|
||||
| maxLength | Number | 524288 | Limits max length accepted in the field |
|
||||
| placeholder | String | - | Placeholder before respondent clicks into field. |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<Phone name="phone" label="Phone" outerClassName="bg-gray-800" />
|
||||
```
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -100,10 +100,13 @@ label: "Do you agree?", value: "Do you agree?"
|
||||
|
||||
## Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ------- | ------ | ------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| options | Array | - | Contains the options in your radio input |
|
||||
| label | String | - | The label (often a question) of the radio input. With no `option` attribute it's also the stored value. |
|
||||
| Prop | Type | Default | Description | |
|
||||
| ---------------- | -------------------- | ------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
||||
| options | Array | - | Contains the options in your radio input | |
|
||||
| label | String | - | The label of the radio input. <br/>With no `option` attribute it's also the stored value. | |
|
||||
| legendClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| optionsClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| optionClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
@@ -124,7 +127,7 @@ label: "Do you agree?", value: "Do you agree?"
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your form with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={Styling}
|
||||
@@ -162,7 +165,7 @@ You can also use Tailwind to extend the classes, like so:
|
||||
/>
|
||||
```
|
||||
|
||||
### Options-specific props
|
||||
### Options-specific props to style it
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ---------------- | -------------------- | --------- | -------------------- | ---------------------------------------------------- |
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,86 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./Search-input-react-form-library-survey-forms-validation-multi-step-forms.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Search Input - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The `Search` input uses HTML's [native search input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/search). It allows a user to enter a search term and is interpreted differently than the normal `text` input from the browser, e.g. it adds a little `x` inside the input field to remove the input again.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<Search name="search" />
|
||||
```
|
||||
|
||||
In most cases, it looks something like this:
|
||||
|
||||
```jsx
|
||||
<Search name="search" placeholder="Search..." label="Search" />
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ------------------------------------------------ |
|
||||
| minLength | Number | 0 | Limits min length accepted in the field |
|
||||
| maxLength | Number | 524288 | Limits max length accepted in the field |
|
||||
| placeholder | String | - | Placeholder before respondent clicks into field. |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<Search
|
||||
name="search"
|
||||
placeholder="Search..."
|
||||
label="Search"
|
||||
innerClassName="border-gray-700 border-2 rounded-full"
|
||||
/>
|
||||
```
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -9,11 +9,19 @@ export const meta = {
|
||||
The submit button component is very straight forward:
|
||||
|
||||
```jsx
|
||||
<Submit label="Submit" />
|
||||
<Submit name="submit" label="Submit" />
|
||||
```
|
||||
|
||||
To keep it working make sure that there is **only one Submit button** per form.
|
||||
|
||||
### Adding an icon
|
||||
|
||||
You can add icons **before and after** the button text:
|
||||
|
||||
```jsx
|
||||
<Submit label="Submit" PrefixIcon={BeakerIcon} SuffixIcon={BeakerIcon} />
|
||||
```
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|
||||
@@ -48,7 +48,7 @@ In most cases, it looks something like this:
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your form with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
@@ -56,17 +56,17 @@ You can style your form with adding CSS to the pre-assigned classes. This is how
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — most often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ In most cases, it looks something like this:
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your form with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
@@ -63,17 +63,17 @@ You can style your form with adding CSS to the pre-assigned classes. This is how
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — most often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,81 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./URL-field-input-best-easy-react-form-librari-hook-form-survey.png";
|
||||
|
||||
export const meta = {
|
||||
title: "URL Input - Formbricks React Form Library",
|
||||
};
|
||||
|
||||
The `URL` input uses HTML's [native url input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/url). It allows a user to enter a url.
|
||||
|
||||
Like all other inputs it needs a `name` prop as an unique identifier:
|
||||
|
||||
```jsx
|
||||
<URL name="url" />
|
||||
```
|
||||
|
||||
<Callout title="Consider using Text input" type="note">
|
||||
The reason there is an URL input in HTML is the native URL validation. Since Formbricks offers URL
|
||||
validation out of the box you can remove unneccessary complexity by using the [Text
|
||||
input](/docs/react-form-library/input-text).
|
||||
</Callout>
|
||||
|
||||
### Props & Attributes
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ------------------------------------------------ |
|
||||
| minLength | Number | 0 | Limits min length accepted in the field |
|
||||
| maxLength | Number | 524288 | Limits max length accepted in the field |
|
||||
| placeholder | String | - | Placeholder before respondent clicks into field. |
|
||||
|
||||
### Universal props all inputs have
|
||||
|
||||
| Prop | What is it? | Required? | Shown to respondent? | Comment |
|
||||
| ----------------- | --------------------------------------- | --------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | name of the field | yes | no | It is not shown to respondents but important as a unique identifier to understand which field holds what content. You cannot have two fields with the same name. |
|
||||
| label | label of the field | yes | yes | The label above the input |
|
||||
| help | help text | no | yes | You can add a little help text to each field to provide more detail on how to fill out the field. |
|
||||
| validation | determines how field input is validated | no | depends on field input | If you want to validate the content of a field before the form is sent, you can do so with the validation prop. [read more](/docs/react-form-library/validation-errors) |
|
||||
| id | own identifier for input | no | no | To target your input with css or javascript directly |
|
||||
| outerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| wrapperClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| innerClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| inputClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| helpClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messagesClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
| messageClassName | append styling class | no | - | [read more](/docs/react-form-library/style-tailwind) |
|
||||
|
||||
### Styling with CSS
|
||||
|
||||
You can style your field with adding CSS to the pre-assigned classes. This is how the classes are assigned:
|
||||
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### Styling with Tailwind
|
||||
|
||||
You can also use Tailwind to extend the classes, like so:
|
||||
|
||||
```jsx
|
||||
<URL name="url" label="Company website" outerClassName="bg-gray-800 my-5" />
|
||||
```
|
||||
|
||||
Here are the in-depth guides for [CSS](/docs/react-form-library/style-css) or [Tailwind](/docs/react-form-library/style-tailwind).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,37 +1,56 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import Image from "next/image";
|
||||
import StyleClasses from "./sampleform.png";
|
||||
|
||||
export const meta = {
|
||||
title: "React Form Library",
|
||||
title: "Building React forms just got easy",
|
||||
};
|
||||
|
||||
## Building React forms has never been quicker.
|
||||
|
||||
Every developer works with forms, few like their experience. Building Forms, especially in React, can be pretty annoying. State management, validation, form components, accessibility, internationalization and performance are all things you have to deal with, but don't really want to.
|
||||
|
||||
We make building - and maintaining - forms easier than ever in the React world.
|
||||
We make building - and maintaining - forms easier than ever in the world of React.
|
||||
|
||||
### Formbricks React Example:
|
||||
### Example
|
||||
|
||||
```jsx
|
||||
import { Form, Text, Textarea, Submit } from "@formbricks/react";
|
||||
import { Form, Text, Email, Checkbox, Submit } from "@formbricks/react";
|
||||
import "@formbricks/react/styles.css";
|
||||
|
||||
export default function WaitlistForm() {
|
||||
return (
|
||||
<Form onSubmit={({ data, schema }) => console.log("data:", data, "schema:", schema)}>
|
||||
<Text name="firstname" label="What's your first name?" validation="required" />
|
||||
<Text name="lastname" label="What's your last name?" />
|
||||
<Textarea name="about" label="About you" help="Please keep it short" />
|
||||
<Submit label="Submit" />
|
||||
<Text name="name" label="What's your name?" validation="required" />
|
||||
<Email
|
||||
name="email"
|
||||
label="What's your email address?"
|
||||
placeholder="you@example.com"
|
||||
validation="required|email"
|
||||
/>
|
||||
<Checkbox
|
||||
name="terms"
|
||||
label="Terms & Conditions"
|
||||
help="To use our service, please accept."
|
||||
validation="accepted"
|
||||
/>
|
||||
<Submit label="Let's go!" />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2">
|
||||
<Image
|
||||
src={StyleClasses}
|
||||
alt="Data log of a form created with the fastest react form builder"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
### Why is this easier already?
|
||||
|
||||
- One easy to use syntax for input types including labels, validation and help texts
|
||||
- One easy to use syntax for all input types
|
||||
- HTML & non-HTML input types available out of the box
|
||||
- Easily maintainable with component-based approach
|
||||
- All characteristics adjustable via props
|
||||
@@ -43,8 +62,12 @@ export default function WaitlistForm() {
|
||||
- Multi-page forms
|
||||
- Accessibility
|
||||
- Internationalization
|
||||
- Form Templates
|
||||
- Form Templates (content & styles)
|
||||
|
||||
The Formbricks React Library uses [React Hook Form](https://react-hook-form.com/) to benefit from their easy to use data handling and performance optimizations. The easy to use approach was inspired by the [FormKit for Vue.js](https://formkit.com/) Library.
|
||||
### Shoutout
|
||||
|
||||
The Formbricks React Library is built on top of [React Hook Form](https://react-hook-form.com/) to make from their data handling and performance optimizations.
|
||||
|
||||
The developer experience is inspired by the great [FormKit for Vue.js](https://formkit.com/) Library.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -84,17 +84,17 @@ Each form element component follows the same naming convention. This means that
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — most often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
| CSS Class | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| formbricks-form | The outermost wrapping element. |
|
||||
| formbricks-outer | A wrapper around the label input, help text and error messages. |
|
||||
| formbricks-help | The help text itself. |
|
||||
| formbricks-wrapper | A wrapper around the label and the input field (no help text). |
|
||||
| formbricks-label | The label itself. |
|
||||
| formbricks-inner | A wrapper around the input element. |
|
||||
| formbricks-input | The input element itself. |
|
||||
| formbricks-message | The element (or many elements) containing a message — often validation and error messages. |
|
||||
| formbricks-messages | A wrapper around all the messages. |
|
||||
|
||||
### In React app, a simple form with one field looks like this:
|
||||
|
||||
|
||||
@@ -16,16 +16,19 @@ We love Tailwind! This is why Formbricks React natively supports Tailwind. All y
|
||||
|
||||
Here are all the props you can use to extend the styling of the different form elements:
|
||||
|
||||
| CSS class | Prop | Content |
|
||||
| ------------------- | ----------------- | --------------------------------------------------- |
|
||||
| formbricks-form | formClassName | The wrapper around the complete form |
|
||||
| formbricks-outer | outerClassName | The wrapper around label, input field and help text |
|
||||
| formbricks-help | helpClassName | The help text |
|
||||
| formbricks-wrapper | wrapperClassName | The wrapper around the label and the input field |
|
||||
| formbricks-label | labelClassName | The label |
|
||||
| formbricks-inner | innerClassName | The input field |
|
||||
| formbricks-input | inputClassName | The input |
|
||||
| formbricks-message | messageClassName | The validation / error message itself |
|
||||
| formbricks-messages | messagesClassName | Wrapper around all error messages |
|
||||
| CSS class | Prop | Content |
|
||||
| ------------------- | ----------------- | ------------------------------------------------------------ |
|
||||
| formbricks-form | formClassName | The wrapper around the complete form |
|
||||
| formbricks-outer | outerClassName | The wrapper around label, input field and help text |
|
||||
| formbricks-legend | legendClassName | The label of the options group (only radio & checkbox input) |
|
||||
| formbricks-help | helpClassName | The help text |
|
||||
| formbricks-options | optionsClassName | A wrapper around all options (only radio & checkbox input) |
|
||||
| formbricks-option | optionClassName | A wrapper around each option (only radio & checkbox input) |
|
||||
| formbricks-wrapper | wrapperClassName | The wrapper around the label and the input field |
|
||||
| formbricks-label | labelClassName | The label |
|
||||
| formbricks-inner | innerClassName | The input field |
|
||||
| formbricks-input | inputClassName | The input |
|
||||
| formbricks-message | messageClassName | The validation / error message itself |
|
||||
| formbricks-messages | messagesClassName | Wrapper around all error messages |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
||||
@@ -12,7 +12,7 @@ Validation prevents users from submitting missing of false data.
|
||||
|
||||
To add a validation to your inputs, add the `validation` prop and write the rules in string syntax. Rules are divided by a pipe (`|`), e.g.:
|
||||
|
||||
```bash
|
||||
```jsx
|
||||
<Text name="age" label="What's your age?" validation="required|number|min:0|max:100" />
|
||||
```
|
||||
|
||||
@@ -27,12 +27,15 @@ Only if all four requirements are met, the form can be submitted. If not an erro
|
||||
|
||||
### Available rules
|
||||
|
||||
| Rule | Explanation | Example |
|
||||
| -------- | -------------------------------------------------------------------------- | ---------- |
|
||||
| required | Only accepts non-empty fields | “required” |
|
||||
| number | Only accepts fields with a number or float value | “number” |
|
||||
| min | Only accepts number values that are greater or equal to the value provided | “min:10” |
|
||||
| max | Only accepts number values that are greater or equal to the value provided | “max:50” |
|
||||
| Rule | Explanation | Example |
|
||||
| ------------ | ------------------------------------------------------------------------------------------- | ---------- |
|
||||
| **accepted** | Only accepts `true`, `1`, `"on"`, and `"yes"` as values (useful e.g. for single checkboxes) | "accepted" |
|
||||
| **email** | Only accepts valid email address format | "email" |
|
||||
| **min** | Only accepts number values that are greater or equal to the value provided | "min:10" |
|
||||
| **max** | Only accepts number values that are greater or equal to the value provided | "max:50" |
|
||||
| **number** | Only accepts fields with a number or float value | "number" |
|
||||
| **required** | Only accepts non-empty fields | "required" |
|
||||
| **url** | Only accepts valid url format (including protocol) | "url" |
|
||||
|
||||
### Message position
|
||||
|
||||
|
||||
@@ -28,9 +28,16 @@ All imported components will be included in the production build - even when you
|
||||
| Component | Details | Use |
|
||||
| -------------- | ------------------- | ------------------------------------------- |
|
||||
| `<Form />` | Form Wrapper | Handles the onSubmit action, wraps the form |
|
||||
| `<Email />` | HTML Email Input | Email input |
|
||||
| `<Number />` | HTML Number Input | Integer or decimal value |
|
||||
| `<Password />` | HTML Password Input | Strings of all kind |
|
||||
| `<Phone />` | HTML Tel Input | Phone numbers |
|
||||
| `<Radio />` | Radio Buttons | Single choice |
|
||||
| `<Search />` | HTML Search Input | Search terms |
|
||||
| `<Submit />` | Submit Button | Submits the form |
|
||||
| `<Text />` | HTML Text Input | Single line of text input |
|
||||
| `<Textarea />` | HTML Textarea Input | Multiple lines of text |
|
||||
| `<Submit />` | Submit Button | Submits the form |
|
||||
| `<URL />` | HTML URL Input | Submits the form |
|
||||
|
||||
---
|
||||
|
||||
@@ -38,13 +45,12 @@ All imported components will be included in the production build - even when you
|
||||
|
||||
| Component | Details | Use |
|
||||
| ------------------ | ----------------------------- | ----------------------- |
|
||||
| `<Radio />` | Radio Buttons | Single choice |
|
||||
| `<Checkbox />` | Checkboxes | Multiple choice |
|
||||
| `<Rating />` | Star-Rating | Simple rating in steps |
|
||||
| `<Nps />` | Nps Score | Evaluate experience |
|
||||
| `<Color />` | Color-Picker | Let user choose a color |
|
||||
| `<Slider />` | Slider | Stepless rating |
|
||||
| `<Autocomplete />` | Autocomplete possible options | e.g. Tags |
|
||||
| `<Payments />` | Ready-made Stripe integration | Process Stripe payments |
|
||||
|
||||
and many more...
|
||||
|
||||
|
||||
@@ -58,9 +58,9 @@ const features = [
|
||||
|
||||
const FormHQPage = () => (
|
||||
<Layout
|
||||
title="FormHQ"
|
||||
title="Formbricks HQ"
|
||||
description="Manage all form data in one place. Analyze right here or pipe your data where you need it.">
|
||||
<HeroTitle headingPt1="Form" headingTeal="HQ" />
|
||||
<HeroTitle headingPt1="Formbricks" headingTeal="HQ" />
|
||||
<Image
|
||||
src={ImageFormHQ}
|
||||
alt="Formbricks HQ user interface to create forms, manage submissions open source."
|
||||
|
||||
4
apps/hq/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["formbricks"],
|
||||
};
|
||||
37
apps/hq/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
.vscode
|
||||
9
apps/hq/CHANGELOG.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# @formbricks/hq
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bcecdc0]
|
||||
- @formbricks/charts@0.1.0
|
||||
- @formbricks/react@0.3.0
|
||||
41
apps/hq/Dockerfile
Normal file
@@ -0,0 +1,41 @@
|
||||
# Add lockfile and package.json's of isolated subworkspace
|
||||
FROM node:16-alpine AS installer
|
||||
RUN apk update
|
||||
RUN apk --no-cache add curl libc6-compat
|
||||
RUN curl -fsSL "https://github.com/pnpm/pnpm/releases/latest/download/pnpm-linuxstatic-x64" -o /bin/pnpm; chmod +x /bin/pnpm;
|
||||
WORKDIR /app
|
||||
|
||||
# First install the dependencies (as they change less often)
|
||||
COPY . .
|
||||
# Copy .env file because Docker don't follow symlinks
|
||||
COPY .env /app/apps/hq/
|
||||
|
||||
RUN pnpm install
|
||||
|
||||
# Build the project
|
||||
RUN pnpm dlx prisma generate
|
||||
RUN pnpm turbo run build --filter=hq...
|
||||
|
||||
FROM node:16-alpine AS runner
|
||||
|
||||
RUN apk --no-cache add curl libc6-compat
|
||||
RUN curl -fsSL "https://github.com/pnpm/pnpm/releases/latest/download/pnpm-linuxstatic-x64" -o /bin/pnpm; chmod +x /bin/pnpm;
|
||||
|
||||
# Don't run production as root
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
USER nextjs
|
||||
|
||||
WORKDIR /home/nextjs
|
||||
|
||||
COPY --from=installer /app/apps/hq/next.config.js .
|
||||
COPY --from=installer /app/apps/hq/package.json .
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/hq/.next/standalone ./
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/hq/.next/static ./apps/hq/.next/static
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/hq/public ./apps/hq/public
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/packages/database/prisma ./packages/database/prisma
|
||||
|
||||
CMD pnpm dlx prisma migrate deploy && node apps/hq/server.js
|
||||
80
apps/hq/README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Formbricks HQ
|
||||
|
||||
> still in development
|
||||
|
||||
Everything you always wanted (from a form tool)...
|
||||
|
||||
The days of scattered response data are counted. Manage all form data in one place. Analyze right here or pipe your data where you need it.
|
||||
|
||||
### How to run locally (for development)
|
||||
|
||||
To get the project running locally on your machine you need to have the following development tools installed:
|
||||
|
||||
- Node.JS (we recommend v16)
|
||||
- [pnpm](https://pnpm.io/)
|
||||
- [Docker](https://www.docker.com/) (to run PostgreSQL / MailHog)
|
||||
|
||||
1. Clone the project:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/formbricks/formbricks
|
||||
```
|
||||
|
||||
and move into the directory
|
||||
|
||||
```sh
|
||||
cd formbricks
|
||||
```
|
||||
|
||||
2. Install Node.JS packages via pnpm. Don't have pnpm? Get it [here](https://pnpm.io/installation)
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. To make the process of installing a dev dependencies easier, we offer a [`docker-compose.yml`](https://docs.docker.com/compose/) with the following servers:
|
||||
|
||||
- a `postgres` container and environment variables preset to reach it,
|
||||
- a `mailhog` container that acts as a mock SMTP server and shows received mails in a web UI (forwarded to your host's `localhost:8025`)
|
||||
|
||||
```sh
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
4. Create a `.env` file based on `.env.example` and change it according to your setup. If you are using a cloud based database or another mail server, you will need to update the `DATABASE_URL` and SMTP settings in your `.env` accordingly.
|
||||
|
||||
```sh
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
5. Make sure your PostgreSQL Database Server is running. Then let prisma set up the database for you:
|
||||
|
||||
```sh
|
||||
pnpm dlx prisma migrate dev
|
||||
```
|
||||
|
||||
6. Start the development server:
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
**You can now access the app on [https://localhost:3000](https://localhost:3000)**. You will be automatically redirected to the login. To use your local installation of formbricks, create a new account.
|
||||
|
||||
For viewing the confirmation email and other emails the system sends you, you can access mailhog at [https://localhost:8025](https://localhost:8025)
|
||||
|
||||
### Build
|
||||
|
||||
To build all apps and packages, run the following command:
|
||||
|
||||
```sh
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Develop
|
||||
|
||||
To develop all apps and packages, run the following command:
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
5
apps/hq/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
36
apps/hq/next.config.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
*/
|
||||
|
||||
var path = require("path");
|
||||
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
output: "standalone",
|
||||
experimental: {
|
||||
outputFileTracingRoot: path.join(__dirname, "../../"),
|
||||
/* serverComponentsExternalPackages: ["@prisma/client"], */
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "avatars.githubusercontent.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
webpack: (config) => {
|
||||
config.externals = [...(config.externals || []), "@prisma/client"];
|
||||
// Important: return the modified config
|
||||
return config;
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
source: "/",
|
||||
destination: "/app/",
|
||||
permanent: false,
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
47
apps/hq/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@formbricks/hq",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formbricks/charts": "workspace:*",
|
||||
"@formbricks/react": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@headlessui/react": "^1.7.4",
|
||||
"@heroicons/react": "^2.0.13",
|
||||
"@vercel/analytics": "^0.1.5",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"clsx": "^1.2.1",
|
||||
"date-fns": "^2.29.3",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"next": "^13.0.5",
|
||||
"next-auth": "^4.17.0",
|
||||
"nextjs-cors": "^2.1.2",
|
||||
"nodemailer": "^6.8.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.6.0",
|
||||
"react-loader-spinner": "^5.3.4",
|
||||
"react-toastify": "^9.1.1",
|
||||
"swr": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/database": "workspace:*",
|
||||
"@formbricks/tailwind-config": "workspace:*",
|
||||
"@formbricks/tsconfig": "workspace:*",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
"postcss": "^8.4.19",
|
||||
"typescript": "^4.9.3"
|
||||
}
|
||||
}
|
||||
1507
apps/hq/pnpm-lock.yaml
generated
Normal file
6
apps/hq/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
BIN
apps/hq/public/favicon/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
apps/hq/public/favicon/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
apps/hq/public/favicon/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
9
apps/hq/public/favicon/browserconfig.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#0f172a</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
apps/hq/public/favicon/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 891 B |
BIN
apps/hq/public/favicon/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
apps/hq/public/favicon/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
apps/hq/public/favicon/mstile-144x144.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
apps/hq/public/favicon/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
apps/hq/public/favicon/mstile-310x150.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
apps/hq/public/favicon/mstile-310x310.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
apps/hq/public/favicon/mstile-70x70.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
24
apps/hq/public/favicon/safari-pinned-tab.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2030 6463 c-392 -63 -688 -348 -758 -728 -4 -22 -7 -269 -7 -550 l0
|
||||
-510 1815 1 c998 0 1842 3 1875 7 139 14 256 58 386 143 266 175 404 445 395
|
||||
774 -8 281 -111 488 -340 683 -47 41 -166 105 -246 133 -153 54 -123 53 -1665
|
||||
52 -786 -1 -1441 -3 -1455 -5z"/>
|
||||
<path d="M1260 3500 l0 -896 1843 1 c1013 1 1865 5 1892 10 28 4 89 20 137 36
|
||||
302 98 527 355 595 679 3 14 6 82 8 151 8 263 -74 468 -260 655 -103 104 -207
|
||||
170 -337 213 -135 45 -91 44 -2025 46 l-1853 2 0 -897z"/>
|
||||
<path d="M1263 2314 c-6 -17 2 -1036 9 -1059 3 -11 11 -40 17 -65 27 -105 104
|
||||
-256 171 -334 184 -216 432 -328 708 -321 142 4 171 8 270 41 313 105 532 351
|
||||
597 672 14 70 16 153 16 573 0 270 -2 494 -6 497 -4 4 -405 7 -892 7 -649 0
|
||||
-887 -3 -890 -11z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
19
apps/hq/public/favicon/site.webmanifest
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
67
apps/hq/src/components/AnalyticsCard.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
"use client";
|
||||
|
||||
import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline";
|
||||
import { ArrowDownIcon, ArrowUpIcon } from "@heroicons/react/24/solid";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
value: string | number;
|
||||
label: string;
|
||||
toolTipText?: string;
|
||||
trend?: number;
|
||||
smallerText?: boolean;
|
||||
}
|
||||
|
||||
const AnalyticsCard: React.FC<Props> = ({ value, label, toolTipText, trend, smallerText }) => {
|
||||
return (
|
||||
<div className="rounded-md bg-white shadow-md">
|
||||
<div key={label} className="px-4 py-5 sm:p-6">
|
||||
<dt className="has-tooltip inline-flex text-base font-normal text-gray-900">
|
||||
{label}{" "}
|
||||
{toolTipText && (
|
||||
<QuestionMarkCircleIcon className="text-red hover:text-ui-gray-dark ml-1 h-4 w-4" />
|
||||
)}
|
||||
{toolTipText && (
|
||||
<span className="tooltip -mt-6 -ml-8 flex grow rounded bg-gray-600 p-1 px-4 text-center text-xs text-white shadow-lg">
|
||||
{toolTipText}
|
||||
</span>
|
||||
)}
|
||||
</dt>
|
||||
<dd className="mt-1 flex items-baseline justify-between md:block lg:flex">
|
||||
<div
|
||||
className={clsx(
|
||||
smallerText ? "text-lg" : "text-xl",
|
||||
"flex items-baseline text-xl font-semibold text-gray-800"
|
||||
)}>
|
||||
{value}
|
||||
</div>
|
||||
|
||||
{trend && (
|
||||
<div
|
||||
className={clsx(
|
||||
trend >= 0 ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800",
|
||||
"inline-flex items-baseline rounded-full px-2.5 py-0.5 text-sm font-medium md:mt-2 lg:mt-0"
|
||||
)}>
|
||||
{trend >= 0 ? (
|
||||
<ArrowUpIcon
|
||||
className="-ml-1 mr-0.5 h-5 w-5 flex-shrink-0 self-center text-green-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : (
|
||||
<ArrowDownIcon
|
||||
className="-ml-1 mr-0.5 h-5 w-5 flex-shrink-0 self-center text-red-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<span className="sr-only">{trend >= 0 ? "Increased" : "Decreased"} by</span>
|
||||
{trend} %
|
||||
</div>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnalyticsCard;
|
||||
39
apps/hq/src/components/EmptyPageFiller.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@formbricks/ui";
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
alertText: string;
|
||||
hintText: string;
|
||||
buttonText?: string;
|
||||
borderStyles?: string;
|
||||
hasButton?: boolean;
|
||||
}
|
||||
|
||||
const EmptyPageFiller: React.FC<Props> = ({
|
||||
children,
|
||||
onClick = () => {},
|
||||
alertText,
|
||||
hintText,
|
||||
buttonText,
|
||||
borderStyles,
|
||||
hasButton = false,
|
||||
}) => {
|
||||
return (
|
||||
<div className={`mx-auto mt-8 rounded-lg border border-slate-200 p-8 text-center ` + borderStyles}>
|
||||
{children}
|
||||
<h3 className="mt-5 text-base font-bold text-slate-400">{alertText}</h3>
|
||||
<p className="mt-1 text-xs font-light text-slate-400">{hintText}</p>
|
||||
{hasButton && (
|
||||
<div className="mt-6">
|
||||
<Button onClick={onClick}>{buttonText}</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyPageFiller;
|
||||
7
apps/hq/src/components/LoadingSpinner.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { TailSpin } from "react-loader-spinner";
|
||||
|
||||
export default function LoadingSpinner() {
|
||||
return <TailSpin color="#1f2937" height={30} width={30} />;
|
||||
}
|
||||