diff --git a/apps/docs/app/global/hidden-fields/filled-hidden-fields.webp b/apps/docs/app/global/hidden-fields/filled-hidden-fields.webp
new file mode 100644
index 0000000000..1881351586
Binary files /dev/null and b/apps/docs/app/global/hidden-fields/filled-hidden-fields.webp differ
diff --git a/apps/docs/app/global/hidden-fields/hidden-field-responses.webp b/apps/docs/app/global/hidden-fields/hidden-field-responses.webp
new file mode 100644
index 0000000000..0d01d48e74
Binary files /dev/null and b/apps/docs/app/global/hidden-fields/hidden-field-responses.webp differ
diff --git a/apps/docs/app/global/hidden-fields/hidden-fields.webp b/apps/docs/app/global/hidden-fields/hidden-fields.webp
new file mode 100644
index 0000000000..6c4dc4ab8d
Binary files /dev/null and b/apps/docs/app/global/hidden-fields/hidden-fields.webp differ
diff --git a/apps/docs/app/global/hidden-fields/input-hidden-fields.webp b/apps/docs/app/global/hidden-fields/input-hidden-fields.webp
new file mode 100644
index 0000000000..8f3d4e45a9
Binary files /dev/null and b/apps/docs/app/global/hidden-fields/input-hidden-fields.webp differ
diff --git a/apps/docs/app/global/hidden-fields/page.mdx b/apps/docs/app/global/hidden-fields/page.mdx
new file mode 100644
index 0000000000..e47f7f521c
--- /dev/null
+++ b/apps/docs/app/global/hidden-fields/page.mdx
@@ -0,0 +1,79 @@
+import { MdxImage } from "@/components/MdxImage";
+
+import FilledHiddenFields from "./filled-hidden-fields.webp";
+import HiddenFieldResponses from "./hidden-field-responses.webp";
+import HiddenFields from "./hidden-fields.webp";
+import InputHiddenFields from "./input-hidden-fields.webp";
+
+export const metadata = {
+ title: "Hidden Fields",
+ description: "Add hidden fields to your surveys to capture additional data without requiring user inputs!",
+};
+
+# Hidden Fields
+
+Hidden fields are a powerful feature in Formbricks that allows you to add data to a submission without asking the user to type it in. This feature is especially useful when you already have information about a user that you want to use in the analysis of the survey results (e.g. `payment plan` or `email`)
+
+Hidden fields are now available in the Formbricks in-app and website surveys as well
+
+## How to Add Hidden Fields
+
+### Enable them in the Survey Builder
+
+1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
+
+
+
+2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
+
+
+
+
+
+### Set Hidden Field
+
+
+
+
+```sh
+formbricks.track("my event", {
+ hiddenFields: {
+ screen: "landing_page",
+ job: "Founder"
+ },
+});
+```
+
+
+
+
+## View Hidden Fields in Responses
+
+These hidden fields will now be visible in the responses tab just like other fields in the Summary as well as the Response Cards, and you can use them to filter and analyze your responses.
+
+
+
+## Use Cases
+
+- **User Metadata**: You can add hidden fields to capture user metadata such as user ID, email, or any other user-specific information.
+- **Survey Metadata**: You can add hidden fields to capture other metadata, e.g. the screen from which the survey was filled, or any other app specific information.
diff --git a/apps/docs/app/link-surveys/hidden-fields/page.mdx b/apps/docs/app/link-surveys/hidden-fields/page.mdx
index 38e83474fc..d37c391486 100644
--- a/apps/docs/app/link-surveys/hidden-fields/page.mdx
+++ b/apps/docs/app/link-surveys/hidden-fields/page.mdx
@@ -4,7 +4,6 @@ import FilledHiddenFields from "./filled-hidden-fields.webp";
import HiddenFieldResponses from "./hidden-field-responses.webp";
import HiddenFields from "./hidden-fields.webp";
import InputHiddenFields from "./input-hidden-fields.webp";
-import SettingsPage from "./settings.webp";
export const metadata = {
title: "Hidden Fields",
@@ -21,16 +20,7 @@ Hidden fields are a powerful feature in Formbricks that allows you to add data t
### Enable them in the Survey Builder
-1. Edit the survey you want to add hidden fields to & open it's settings, make sure it's selected as a **Link Survey**.
-
-
-
-2. Switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
+1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
-3. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
+2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
= [
{ title: "Advanced Targeting", href: "/app-surveys/advanced-targeting" },
{ title: "Show Survey to % of users", href: "/global/show-survey-to-percent-of-users" }, // app and website
{ title: "Recontact Options", href: "/app-surveys/recontact" },
+ { title: "Hidden Fields", href: "/global/hidden-fields" }, // global
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" }, // global
{ title: "User Metadata", href: "/global/metadata" }, // global
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
@@ -57,6 +58,7 @@ export const navigation: Array = [
{ title: "Actions & Targeting", href: "/website-surveys/actions-and-targeting" },
{ title: "Show Survey to % of users", href: "/global/show-survey-to-percent-of-users" }, // app and website
{ title: "Recontact Options", href: "/app-surveys/recontact" },
+ { title: "Hidden Fields", href: "/global/hidden-fields" }, // global
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" }, // global
{ title: "User Metadata", href: "/global/metadata" }, // global
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/QuestionsView.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/QuestionsView.tsx
index 68047b57fe..e4749961e1 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/QuestionsView.tsx
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/QuestionsView.tsx
@@ -383,14 +383,12 @@ export const QuestionsView = ({
attributeClasses={attributeClasses}
/>
- {localSurvey.type === "link" ? (
-
- ) : null}
+
(() => {
- const fieldsRecord: TResponseData = {};
- let fieldsSet = false;
+ const hiddenFieldsRecord = useMemo(() => {
+ const fieldsRecord: TResponseHiddenFieldValue = {};
survey.hiddenFields?.fieldIds?.forEach((field) => {
const answer = searchParams?.get(field);
if (answer) {
fieldsRecord[field] = answer;
- fieldsSet = true;
}
});
- // Only return the record if at least one field was set.
- return fieldsSet ? fieldsRecord : undefined;
+ return fieldsRecord;
}, [searchParams, survey.hiddenFields?.fieldIds]);
const getVerifiedEmail = useMemo | null>(() => {
@@ -255,7 +252,6 @@ export const LinkSurvey = ({
responseQueue.add({
data: {
...responseUpdate.data,
- ...hiddenFieldsRecord,
...getVerifiedEmail,
},
ttc: responseUpdate.ttc,
@@ -266,6 +262,7 @@ export const LinkSurvey = ({
url: window.location.href,
source: sourceParam || "",
},
+ ...(Object.keys(hiddenFieldsRecord).length > 0 && { hiddenFields: hiddenFieldsRecord }),
});
}}
onFileUpload={async (file: File, params: TUploadFileConfig) => {
@@ -285,7 +282,6 @@ export const LinkSurvey = ({
setQuestionId = f;
}}
startAtQuestionId={startAt && isStartAtValid ? startAt : undefined}
- hiddenFieldsRecord={hiddenFieldsRecord}
/>
diff --git a/packages/js-core/src/app/index.ts b/packages/js-core/src/app/index.ts
index 978b7cac5d..5b5024b6df 100644
--- a/packages/js-core/src/app/index.ts
+++ b/packages/js-core/src/app/index.ts
@@ -1,4 +1,4 @@
-import { TJsAppConfigInput } from "@formbricks/types/js";
+import { TJsAppConfigInput, TJsTrackProperties } from "@formbricks/types/js";
import { CommandQueue } from "../shared/commandQueue";
import { ErrorHandler } from "../shared/errors";
@@ -41,7 +41,7 @@ const reset = async (): Promise => {
await queue.wait();
};
-const track = async (name: string, properties: any = {}): Promise => {
+const track = async (name: string, properties?: TJsTrackProperties): Promise => {
queue.add(true, "app", trackCodeAction, name, properties);
await queue.wait();
};
diff --git a/packages/js-core/src/app/lib/actions.ts b/packages/js-core/src/app/lib/actions.ts
index 2ec6705c19..865d9a3612 100644
--- a/packages/js-core/src/app/lib/actions.ts
+++ b/packages/js-core/src/app/lib/actions.ts
@@ -1,5 +1,5 @@
import { FormbricksAPI } from "@formbricks/api";
-import { TJsActionInput } from "@formbricks/types/js";
+import { TJsActionInput, TJsTrackProperties } from "@formbricks/types/js";
import { InvalidCodeError, NetworkError, Result, err, okVoid } from "../../shared/errors";
import { Logger } from "../../shared/logger";
@@ -13,7 +13,11 @@ const inAppConfig = AppConfig.getInstance();
const intentsToNotCreateOnApp = ["Exit Intent (Desktop)", "50% Scroll"];
-export const trackAction = async (name: string, alias?: string): Promise> => {
+export const trackAction = async (
+ name: string,
+ alias?: string,
+ properties?: TJsTrackProperties
+): Promise> => {
const aliasName = alias || name;
const { userId } = inAppConfig.get();
@@ -71,7 +75,7 @@ export const trackAction = async (name: string, alias?: string): Promise> | Result => {
const {
state: { actionClasses = [] },
@@ -99,7 +104,7 @@ export const trackCodeAction = (
});
}
- return trackAction(action.name, code);
+ return trackAction(action.name, code, properties);
};
export const trackNoCodeAction = (name: string): Promise> => {
diff --git a/packages/js-core/src/app/lib/widget.ts b/packages/js-core/src/app/lib/widget.ts
index 2c967bf741..ae05160f8e 100644
--- a/packages/js-core/src/app/lib/widget.ts
+++ b/packages/js-core/src/app/lib/widget.ts
@@ -2,12 +2,13 @@ import { FormbricksAPI } from "@formbricks/api";
import { ResponseQueue } from "@formbricks/lib/responseQueue";
import { SurveyState } from "@formbricks/lib/surveyState";
import { getStyling } from "@formbricks/lib/utils/styling";
-import { TResponseUpdate } from "@formbricks/types/responses";
+import { TJsTrackProperties } from "@formbricks/types/js";
+import { TResponseHiddenFieldValue, TResponseUpdate } from "@formbricks/types/responses";
import { TSurvey } from "@formbricks/types/surveys";
import { ErrorHandler } from "../../shared/errors";
import { Logger } from "../../shared/logger";
-import { getDefaultLanguageCode, getLanguageCode } from "../../shared/utils";
+import { getDefaultLanguageCode, getLanguageCode, handleHiddenFields } from "../../shared/utils";
import { AppConfig } from "./config";
import { putFormbricksInErrorState } from "./initialize";
import { sync } from "./sync";
@@ -30,7 +31,11 @@ const shouldDisplayBasedOnPercentage = (displayPercentage: number) => {
return randomNum <= displayPercentage;
};
-export const triggerSurvey = async (survey: TSurvey, action?: string): Promise => {
+export const triggerSurvey = async (
+ survey: TSurvey,
+ action?: string,
+ properties?: TJsTrackProperties
+): Promise => {
// Check if the survey should be displayed based on displayPercentage
if (survey.displayPercentage) {
const shouldDisplaySurvey = shouldDisplayBasedOnPercentage(survey.displayPercentage);
@@ -39,10 +44,20 @@ export const triggerSurvey = async (survey: TSurvey, action?: string): Promise {
+const renderWidget = async (
+ survey: TSurvey,
+ action?: string,
+ hiddenFields: TResponseHiddenFieldValue = {}
+) => {
if (isSurveyRunning) {
logger.debug("A survey is already running. Skipping.");
return;
@@ -95,8 +110,8 @@ const renderWidget = async (survey: TSurvey, action?: string) => {
setTimeout(() => {
formbricksSurveys.renderSurveyModal({
- survey: survey,
- isBrandingEnabled: isBrandingEnabled,
+ survey,
+ isBrandingEnabled,
clickOutside,
darkOverlay,
languageCode,
@@ -144,6 +159,7 @@ const renderWidget = async (survey: TSurvey, action?: string) => {
url: window.location.href,
action,
},
+ hiddenFields,
});
},
onClose: closeSurvey,
diff --git a/packages/js-core/src/shared/utils.ts b/packages/js-core/src/shared/utils.ts
index a9de068182..dc8a7bb74c 100644
--- a/packages/js-core/src/shared/utils.ts
+++ b/packages/js-core/src/shared/utils.ts
@@ -1,6 +1,12 @@
import { TAttributes } from "@formbricks/types/attributes";
+import { TJsTrackProperties } from "@formbricks/types/js";
+import { TResponseHiddenFieldValue } from "@formbricks/types/responses";
import { TSurvey } from "@formbricks/types/surveys";
+import { Logger } from "../shared/logger";
+
+const logger = Logger.getInstance();
+
export const getIsDebug = () => window.location.search.includes("formbricksDebug=true");
export const getLanguageCode = (survey: TSurvey, attributes: TAttributes): string | undefined => {
@@ -34,3 +40,34 @@ export const getDefaultLanguageCode = (survey: TSurvey) => {
});
if (defaultSurveyLanguage) return defaultSurveyLanguage.language.code;
};
+
+export const handleHiddenFields = (
+ hiddenFieldsConfig: TSurvey["hiddenFields"],
+ hiddenFields: TJsTrackProperties["hiddenFields"]
+): TResponseHiddenFieldValue => {
+ const { enabled: enabledHiddenFields, fieldIds: hiddenFieldIds } = hiddenFieldsConfig || {};
+
+ let hiddenFieldsObject: TResponseHiddenFieldValue = {};
+
+ if (!enabledHiddenFields) {
+ logger.error("Hidden fields are not enabled for this survey");
+ } else if (hiddenFieldIds && hiddenFields) {
+ const unknownHiddenFields: string[] = [];
+ hiddenFieldsObject = Object.keys(hiddenFields).reduce((acc, key) => {
+ if (hiddenFieldIds?.includes(key)) {
+ acc[key] = hiddenFields?.[key];
+ } else {
+ unknownHiddenFields.push(key);
+ }
+ return acc;
+ }, {} as TResponseHiddenFieldValue);
+
+ if (unknownHiddenFields.length > 0) {
+ logger.error(
+ `Unknown hidden fields: ${unknownHiddenFields.join(", ")}. Please add them to the survey hidden fields.`
+ );
+ }
+ }
+
+ return hiddenFieldsObject;
+};
diff --git a/packages/js-core/src/website/index.ts b/packages/js-core/src/website/index.ts
index 50436d2099..b2c14ed9b3 100644
--- a/packages/js-core/src/website/index.ts
+++ b/packages/js-core/src/website/index.ts
@@ -1,4 +1,4 @@
-import { TJsWebsiteConfigInput } from "@formbricks/types/js";
+import { TJsTrackProperties, TJsWebsiteConfigInput } from "@formbricks/types/js";
// Shared imports
import { CommandQueue } from "../shared/commandQueue";
@@ -26,7 +26,7 @@ const reset = async (): Promise => {
await queue.wait();
};
-const track = async (name: string, properties: any = {}): Promise => {
+const track = async (name: string, properties?: TJsTrackProperties): Promise => {
queue.add(true, "website", trackCodeAction, name, properties);
await queue.wait();
};
diff --git a/packages/js-core/src/website/lib/actions.ts b/packages/js-core/src/website/lib/actions.ts
index cb79da3542..b9b98dcc49 100644
--- a/packages/js-core/src/website/lib/actions.ts
+++ b/packages/js-core/src/website/lib/actions.ts
@@ -1,3 +1,5 @@
+import { TJsTrackProperties } from "@formbricks/types/js";
+
import { InvalidCodeError, NetworkError, Result, err, okVoid } from "../../shared/errors";
import { Logger } from "../../shared/logger";
import { WebsiteConfig } from "./config";
@@ -6,7 +8,11 @@ import { triggerSurvey } from "./widget";
const logger = Logger.getInstance();
const websiteConfig = WebsiteConfig.getInstance();
-export const trackAction = async (name: string, alias?: string): Promise> => {
+export const trackAction = async (
+ name: string,
+ alias?: string,
+ properties?: TJsTrackProperties
+): Promise> => {
const aliasName = alias || name;
logger.debug(`Formbricks: Action "${aliasName}" tracked`);
@@ -17,7 +23,7 @@ export const trackAction = async (name: string, alias?: string): Promise> | Result => {
const {
state: { actionClasses = [] },
@@ -45,7 +52,7 @@ export const trackCodeAction = (
});
}
- return trackAction(action.name, code);
+ return trackAction(action.name, code, properties);
};
export const trackNoCodeAction = (name: string): Promise> => {
diff --git a/packages/js-core/src/website/lib/widget.ts b/packages/js-core/src/website/lib/widget.ts
index 02232175b4..f92c63b4c4 100644
--- a/packages/js-core/src/website/lib/widget.ts
+++ b/packages/js-core/src/website/lib/widget.ts
@@ -2,12 +2,12 @@ import { FormbricksAPI } from "@formbricks/api";
import { ResponseQueue } from "@formbricks/lib/responseQueue";
import { SurveyState } from "@formbricks/lib/surveyState";
import { getStyling } from "@formbricks/lib/utils/styling";
-import { TJSWebsiteStateDisplay } from "@formbricks/types/js";
-import { TResponseUpdate } from "@formbricks/types/responses";
+import { TJSWebsiteStateDisplay, TJsTrackProperties } from "@formbricks/types/js";
+import { TResponseHiddenFieldValue, TResponseUpdate } from "@formbricks/types/responses";
import { TSurvey } from "@formbricks/types/surveys";
import { Logger } from "../../shared/logger";
-import { getDefaultLanguageCode, getLanguageCode } from "../../shared/utils";
+import { getDefaultLanguageCode, getLanguageCode, handleHiddenFields } from "../../shared/utils";
import { WebsiteConfig } from "./config";
import { filterPublicSurveys } from "./sync";
@@ -29,7 +29,11 @@ const shouldDisplayBasedOnPercentage = (displayPercentage: number) => {
return randomNum <= displayPercentage;
};
-export const triggerSurvey = async (survey: TSurvey, action?: string): Promise => {
+export const triggerSurvey = async (
+ survey: TSurvey,
+ action?: string,
+ properties?: TJsTrackProperties
+): Promise => {
// Check if the survey should be displayed based on displayPercentage
if (survey.displayPercentage) {
const shouldDisplaySurvey = shouldDisplayBasedOnPercentage(survey.displayPercentage);
@@ -38,10 +42,20 @@ export const triggerSurvey = async (survey: TSurvey, action?: string): Promise {
+const renderWidget = async (
+ survey: TSurvey,
+ action?: string,
+ hiddenFields: TResponseHiddenFieldValue = {}
+) => {
if (isSurveyRunning) {
logger.debug("A survey is already running. Skipping.");
return;
@@ -94,8 +108,8 @@ const renderWidget = async (survey: TSurvey, action?: string) => {
setTimeout(() => {
formbricksSurveys.renderSurveyModal({
- survey: survey,
- isBrandingEnabled: isBrandingEnabled,
+ survey,
+ isBrandingEnabled,
clickOutside,
darkOverlay,
languageCode,
@@ -175,6 +189,7 @@ const renderWidget = async (survey: TSurvey, action?: string) => {
url: window.location.href,
action,
},
+ hiddenFields,
});
},
onClose: closeSurvey,
diff --git a/packages/lib/responseQueue.ts b/packages/lib/responseQueue.ts
index b8e601af5d..08550572ed 100644
--- a/packages/lib/responseQueue.ts
+++ b/packages/lib/responseQueue.ts
@@ -87,6 +87,7 @@ export class ResponseQueue {
surveyId: this.surveyState.surveyId,
userId: this.surveyState.userId || null,
singleUseId: this.surveyState.singleUseId || null,
+ data: { ...responseUpdate.data, ...responseUpdate.hiddenFields },
});
if (!response.ok) {
throw new Error("Could not create response");
diff --git a/packages/surveys/src/components/general/Survey.tsx b/packages/surveys/src/components/general/Survey.tsx
index 608094cb5a..48c1a0b9f4 100644
--- a/packages/surveys/src/components/general/Survey.tsx
+++ b/packages/surveys/src/components/general/Survey.tsx
@@ -35,7 +35,6 @@ export const Survey = ({
onFileUpload,
responseCount,
startAtQuestionId,
- hiddenFieldsRecord,
clickOutside,
shouldResetQuestionId,
}: SurveyBaseProps) => {
@@ -58,7 +57,7 @@ export const Survey = ({
const [loadingElement, setLoadingElement] = useState(false);
const [history, setHistory] = useState([]);
- const [responseData, setResponseData] = useState(hiddenFieldsRecord ?? {});
+ const [responseData, setResponseData] = useState({});
const [ttc, setTtc] = useState({});
const cardArrangement = useMemo(() => {
if (survey.type === "link") {
diff --git a/packages/types/formbricksSurveys.ts b/packages/types/formbricksSurveys.ts
index f6e80fe696..935e9b0c66 100644
--- a/packages/types/formbricksSurveys.ts
+++ b/packages/types/formbricksSurveys.ts
@@ -24,7 +24,6 @@ export interface SurveyBaseProps {
responseCount?: number;
isCardBorderVisible?: boolean;
startAtQuestionId?: string;
- hiddenFieldsRecord?: TResponseData;
clickOutside?: boolean;
shouldResetQuestionId?: boolean;
}
diff --git a/packages/types/js.ts b/packages/types/js.ts
index 33c9252c8c..365ba1a154 100644
--- a/packages/types/js.ts
+++ b/packages/types/js.ts
@@ -5,6 +5,7 @@ import { ZActionClass } from "./actionClasses";
import { ZAttributes } from "./attributes";
import { ZPerson } from "./people";
import { ZProduct } from "./product";
+import { ZResponseHiddenFieldValue } from "./responses";
import { ZSurvey } from "./surveys";
export const ZJsPerson = z.object({
@@ -252,3 +253,9 @@ export type TSettings = z.infer;
export const ZJsPackageType = z.union([z.literal("app"), z.literal("website")]);
export type TJsPackageType = z.infer;
+
+export const ZJsTrackProperties = z.object({
+ hiddenFields: ZResponseHiddenFieldValue.optional(),
+});
+
+export type TJsTrackProperties = z.infer;
diff --git a/packages/types/responses.ts b/packages/types/responses.ts
index 71fdbd4b89..35cccd5450 100644
--- a/packages/types/responses.ts
+++ b/packages/types/responses.ts
@@ -292,6 +292,9 @@ export const ZResponseWithSurvey = ZResponse.extend({
export type TResponseWithSurvey = z.infer;
+export const ZResponseHiddenFieldValue = z.record(z.union([z.string(), z.number(), z.array(z.string())]));
+export type TResponseHiddenFieldValue = z.infer;
+
export const ZResponseUpdate = z.object({
finished: z.boolean(),
data: ZResponseData,
@@ -304,6 +307,7 @@ export const ZResponseUpdate = z.object({
action: z.string().optional(),
})
.optional(),
+ hiddenFields: ZResponseHiddenFieldValue.optional(),
});
export type TResponseUpdate = z.infer;
diff --git a/packages/ui/PreviewSurvey/index.tsx b/packages/ui/PreviewSurvey/index.tsx
index 97a2e3eace..81aa8a7809 100644
--- a/packages/ui/PreviewSurvey/index.tsx
+++ b/packages/ui/PreviewSurvey/index.tsx
@@ -226,7 +226,7 @@ export const PreviewSurvey = ({
: "expanded_with_fixed_positioning"
: "shrink"
}
- className="relative flex h-[95] max-h-[95%] w-5/6 items-center justify-center rounded-lg border border-slate-300 bg-slate-200">
+ className="relative flex h-[95%] max-h-[95%] w-5/6 items-center justify-center rounded-lg border border-slate-300 bg-slate-200">
{previewMode === "mobile" && (
<>