Gå til indhold

Customization

Renderes undersøgelsen inde i en WebView? Kan vi tilpasse UI’et?

På webben renderes undersøgelsen ikke inde i en WebView. SDK’et injicerer undersøgelsen direkte i DOM’en på din side, inde i det containerelement, du sender til form.generate(...). Det betyder, at:

  • Den er en del af samme DOM-træ som din app.
  • Den kan styles med dit eget CSS og inspiceres med browserens DevTools.
  • Den arver din sides font-stack, tilgængelighedsindstillinger og prefers-reduced-motion.
  • Der er ingen iframe og ingen sandbox.

React Native er vejen anderledes — se React Native — og dér kører undersøgelsen inde i en WebView, fordi RN ikke har en DOM. Det er et hostkrav, ikke en begrænsning i SDK’et.

Du har tre uafhængige tilpasningslag på webben: CSS-variabler, knaplabels og overrides af de genererede CSS-klasser for fuld visuel kontrol.


SDK’et leverer hele sit standardudseende som ét stylesheet på @magicfeedback/native/dist/styles/magicfeedback-default.css. Formularen kræver dette stylesheet for at renderes korrekt — indlæs det én gang i din apps entry og læg dine overrides nedenfor.

Vælg snippet’et der matcher din integration.

Bundler (Vite / Webpack / Rollup / esbuild)

Sektion kaldt “Bundler (Vite / Webpack / Rollup / esbuild)”
// main.ts / index.ts / app.tsx — din entry-fil
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
// Dine egne overrides EFTER SDK-importet, så de vinder specificity-bindinger.
import "./styles/magicfeedback-overrides.css";

Importér stylesheettet fra en 'use client'-komponent eller direkte fra root-layoutet. Pages Router-brugere importerer fra _app.tsx.

app/layout.tsx
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
import "./globals.css"; // dine overrides
export default function RootLayout({ children }) {
return (
<html lang="da">
<body>{children}</body>
</html>
);
}
pages/_app.tsx
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
import "../styles/magicfeedback-overrides.css";
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
<link
rel="stylesheet"
href="./node_modules/@magicfeedback/native/dist/styles/magicfeedback-default.css"
/>
<link rel="stylesheet" href="./assets/magicfeedback-overrides.css" />

Indlæser du SDK’et fra et CDN (fx unpkg eller jsDelivr), så indlæs det matchende stylesheet fra samme CDN.

<link
rel="stylesheet"
href="https://unpkg.com/@magicfeedback/native/dist/styles/magicfeedback-default.css"
/>
<link rel="stylesheet" href="/styles/magicfeedback-overrides.css" />

I React Native kører SDK’et inde i en WebView, som indlæser en lille HTML-side, du hoster. Tilføj standard-stylesheettet (og eventuelle overrides) til den sides <head>. CDN-indlæsning er den enkleste opsætning — der er ingen bundler i WebView’et.

<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://unpkg.com/@magicfeedback/native/dist/styles/magicfeedback-default.css"
/>
<style>
/* Inline overrides — hold WebView'et som én selvstændig fil */
:root {
--mf-primary: #0f766e;
--mf-radius-md: 0.75rem;
}
</style>
</head>
<body>
<div id="survey-root"></div>
<script src="https://unpkg.com/@magicfeedback/native/dist/magicfeedback-sdk.browser.js"></script>
<!-- init + form.generate("survey-root", { ... }) her -->
</body>
</html>

Se React Native for hele WebView-kablingen.

I enhver integration skal SDK-stylesheettet indlæses før dine overrides — ellers kan dine regler tabe specificity-bindinger til SDK’ets standarder.

// ✅ korrekt rækkefølge
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
import "./my-overrides.css";
// ❌ forkert — overrides indlæst først
import "./my-overrides.css";
import "@magicfeedback/native/dist/styles/magicfeedback-default.css";

I multi-side-apps hvor undersøgelsen kun vises på få ruter, kan du udsætte stylesheettet — men sørg for at det er i DOM’en inden form.generate(...) køres, ellers bliver første rendering uden styles.

async function showFeedback() {
if (!document.getElementById("mf-styles")) {
const link = document.createElement("link");
link.id = "mf-styles";
link.rel = "stylesheet";
link.href = "https://unpkg.com/@magicfeedback/native/dist/styles/magicfeedback-default.css";
document.head.appendChild(link);
await new Promise((resolve) => (link.onload = resolve));
}
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
await form.generate("survey-root", { addButton: true });
}

Den hurtigste måde at sætte dit brand på. Tilsidesæt variablerne fra standard-stylesheettet i dit eget CSS — efter SDK-importet.

:root {
--mf-primary: #0f766e;
--mf-primary-hover: #115e59;
--mf-primary-light: #ccfbf1;
--mf-text-primary: #0f172a;
--mf-text-secondary: #475569;
--mf-bg-primary: #ffffff;
--mf-bg-secondary: #f8fafc;
--mf-border: #cbd5e1;
--mf-border-focus: #0f766e;
--mf-radius-md: 0.5rem;
--mf-shadow-md: 0 10px 20px rgba(15, 23, 42, 0.08);
}

Det er de præcise defaults defineret i magicfeedback-default.css. Kopier blokken ind i dit eget stylesheet, ændr kun det du har brug for, og du har en fuldt brandet undersøgelse.

:root {
/* Farver — minimal pastel */
--mf-primary: #1E293B;
--mf-primary-hover: #0F172A;
--mf-primary-light: #E2E8F0;
--mf-text-primary: #1E293B;
--mf-text-secondary: #475569;
--mf-text-muted: #94A3B8;
--mf-bg-primary: #F8FAFC;
--mf-bg-secondary: #FFFFFF;
--mf-bg-hover: #EEF2F6;
--mf-border: #E2E8F0;
--mf-border-focus: #1E293B;
--mf-success: #16A34A;
--mf-error: #EF4444;
--mf-warning: #F59E0B;
--mf-surface: #FFFFFF;
--mf-surface-alt: #F1F5F9;
--mf-accent: #38BDF8;
/* Spacing */
--mf-space-xs: 0.25rem;
--mf-space-sm: 0.5rem;
--mf-space-md: 0.75rem;
--mf-space-lg: 1rem;
--mf-space-xl: 1.5rem;
/* Border radius */
--mf-radius-sm: 0.5rem;
--mf-radius-md: 0.75rem;
--mf-radius-lg: 1.25rem;
--mf-radius-full: 9999px;
/* Skygger */
--mf-shadow-sm: 0 1px 2px 0 rgba(15, 23, 42, 0.06);
--mf-shadow-md: 0 8px 20px rgba(15, 23, 42, 0.08);
--mf-shadow-lg: 0 16px 30px rgba(15, 23, 42, 0.12);
--mf-shadow-focus: 0 0 0 3px rgba(30, 41, 59, 0.15);
--mf-shadow-card: 0 18px 40px rgba(15, 23, 42, 0.08);
/* Typografi */
--mf-font-sans: "Nunito", "Quicksand", "Avenir Next", "Trebuchet MS", sans-serif;
--mf-font-size-sm: 0.875rem;
--mf-font-size-base: 1rem;
--mf-font-size-lg: 1.125rem;
--mf-font-size-xl: 1.25rem;
--mf-line-height: 1.6;
--mf-font-weight-normal: 400;
--mf-font-weight-medium: 500;
--mf-font-weight-semibold: 600;
--mf-font-weight-bold: 700;
--mf-font-weight-extrabold: 800;
/* Transitions */
--mf-transition: all 0.2s ease;
--mf-transition-fast: all 0.15s ease;
}

Match dit dark mode med en anden blok:

@media (prefers-color-scheme: dark) {
:root {
--mf-bg-primary: #0f172a;
--mf-bg-secondary: #111827;
--mf-text-primary: #f8fafc;
--mf-text-secondary: #94a3b8;
--mf-border: #334155;
}
}

Ingen JavaScript involveret. Næste rendering henter de nye variabler.


Send labels til generate(). Brug det til lokalisering eller for at matche dit produkts tone uden at røre CSS.

await form.generate("survey-root", {
addButton: true,
sendButtonText: "Send min feedback",
backButtonText: "Tilbage",
nextButtonText: "Næste",
startButtonText: "Lad os starte",
addSuccessScreen: true,
successMessage: "Tak! Vi har lige modtaget din feedback.",
});

Vil du have fuld kontrol over navigation (egne knapper i eget layout), så deaktivér de indbyggede:

await form.generate("survey-root", { addButton: false });
document.getElementById("next")?.addEventListener("click", () => form.send());
document.getElementById("back")?.addEventListener("click", () => form.back());

Lag 3 — Tilsidesæt de genererede klasser

Sektion kaldt “Lag 3 — Tilsidesæt de genererede klasser”

For dybere visuelle ændringer end variabler kan du tilsidesætte klasserne direkte fra dit eget CSS. SDK’et bruger stabile klassenavne (alle med præfikset magicfeedback-), så det er sikkert at gøre.

Herunder det fulde kort over offentlige klasser leveret af magicfeedback-default.css, grupperet efter hvad de renderer. Alle klasser har præfikset magicfeedback-.

KlasseHvad den styler
.magicfeedback-containerYderste wrapper omkring formularen.
.magicfeedback-form<form>-elementet med spørgsmål og actions.
.magicfeedback-questionsWrapper omkring spørgsmålslisten på den aktuelle side.
.magicfeedback-divEt enkelt spørgsmål — enheden du normalt rammer for spacing eller borders.
.magicfeedback-labelEt spørgsmåls primære titel.
.magicfeedback-sublabelEt spørgsmåls sekundære tekst / hint.
.magicfeedback-errorInline valideringsfejlbesked.
.magicfeedback-counterProgress-indikator (fx “2 af 5”).
.magicfeedback-imageEt billede renderet i et spørgsmål eller en side.
.magicfeedback-warningIkke-blokerende advarselstekst.
KlasseHvad den styler
.magicfeedback-start-messageDen valgfri intro-skærms container.
.magicfeedback-start-message-buttonCTA-knappen på intro-skærmen.
.magicfeedback-info-messageStandalone info-sider.
.magicfeedback-success-messageDen indbyggede “tak”-skærm.
KlasseHvad den styler
.magicfeedback-action-containerAction-baren omkring back / next / submit.
.magicfeedback-submitPrimær submit / next-knap.
.magicfeedback-backSekundær tilbage-knap.
.magicfeedback-buttonGenerisk SDK-knap (brugt i modaler).
.magicfeedback-button-primaryPrimary-variant af den generiske knap.
.magicfeedback-skip-containerWrapper omkring “skip”-checkboxen.
Sektion kaldt “Valg-spørgsmål (RADIO, MULTIPLECHOICE, BOOLEAN, CONSENT)”
KlasseHvad den styler
.magicfeedback-radioContainer til et RADIO-spørgsmål.
.magicfeedback-radio-containerHver radio-option (label + input).
.magicfeedback-checkboxContainer til et MULTIPLECHOICE-spørgsmål.
.magicfeedback-checkbox-containerHver checkbox-option.
.magicfeedback-boolean-containerContainer til et BOOLEAN-spørgsmål.
.magicfeedback-boolean-optionHver yes/no-option.
.magicfeedback-consent-containerEn CONSENT-checkbox + label.

Rating-spørgsmål (RATING_STAR, RATING_EMOJI, RATING_NUMBER)

Sektion kaldt “Rating-spørgsmål (RATING_STAR, RATING_EMOJI, RATING_NUMBER)”
KlasseHvad den styler
.magicfeedback-ratingGenerisk rating-wrapper.
.magicfeedback-rating-containerRække af rating-options.
.magicfeedback-rating-placeholderHjælpetekst under et rating (fx “Slet ikke sandsynligt”).
.magicfeedback-rating-placeholder-valueNumerisk placeholder under et rating.
.magicfeedback-rating-option-label-containerEn enkelt emoji-rating-option.
.magicfeedback-rating-numberWrapper til et RATING_NUMBER-spørgsmål.
.magicfeedback-rating-number-containerRække af numeriske options.
.magicfeedback-rating-number-optionEn enkelt numerisk option.
.magicfeedback-rating-number-option-label-containerLabel/input-parret inde i en numerisk option.
.magicfeedback-rating-number-top-placeholderTop-label på den numeriske skala.
.magicfeedback-rating-number-bottom-placeholderBund-label på den numeriske skala.
.magicfeedback-rating-starWrapper til et RATING_STAR-spørgsmål.
.magicfeedback-rating-star-containerRække af stjerner.
.magicfeedback-rating-star-optionEn enkelt stjerne.
.magicfeedback-rating-star-selectedVisuel state for valgt stjerne.
.rating__starSelve stjerne-glyffen.

Billed-valg-spørgsmål (MULTIPLECHOISE_IMAGE)

Sektion kaldt “Billed-valg-spørgsmål (MULTIPLECHOISE_IMAGE)”
KlasseHvad den styler
.magicfeedback-multiple-choice-image-optionEn enkelt billed-option.
.magicfeedback-image-option-label-containerLabel/input/billede-gruppering.

Matrix-spørgsmål (MULTI_QUESTION_MATRIX)

Sektion kaldt “Matrix-spørgsmål (MULTI_QUESTION_MATRIX)”
KlasseHvad den styler
.magicfeedback-multi-question-matrix-containerWrapper omkring matrixen.
.magicfeedback-multi-question-matrix-tableSelve <table>’en.
.magicfeedback-multi-question-matrix-row-trEn enkelt række.
.magicfeedback-multi-question-matrix-row-labelRækkens venstre-label.
KlasseHvad den styler
.magicfeedback-priority-list-headerHeader-rækken.
.magicfeedback-priority-list-listDen ordnede liste.
.magicfeedback-priority-list-itemEn enkelt flytbar item.
.magicfeedback-priority-list-item-labelItemets label-tekst.
.magicfeedback-priority-list-arrowsOp/ned-pilegruppen.
.magicfeedback-priority-list-arrow-upOp-pil-knap.
.magicfeedback-priority-list-arrow-downNed-pil-knap.
.magicfeedback-priority-list-reorderReorder-affordance-område.
KlasseHvad den styler
.magicfeedback-point-system-itemEn enkelt point-allokerings-række.
.magicfeedback-point-system-input-containerWrapper omkring points-input’et.
.magicfeedback-point-system-total”Brugte points / total”-indikator.
Sektion kaldt “Modal (brugt af nogle sammensatte widgets)”
KlasseHvad den styler
.magicfeedback-modal-backdropDen nedtonede baggrund bag modalen.
.magicfeedback-modalSelve modal-panelet.
.magicfeedback-modal-actionsAction-området inde i modalen.
.magicfeedback-modal-counterProgress-counter inde i modalen.
.magicfeedback-modal-listListe renderet inde i modalen.
.magicfeedback-modal-rowEn enkelt række inde i modal-listen.
.magicfeedback-modal-closeModal close-knap.
KlasseHvad den styler
.magicfeedback-visually-hiddenTekst kun synlig for skærmlæsere.
/* Kompakt spørgsmåls-spacing inde i slim-modaler */
.magicfeedback-div {
margin-bottom: 1rem;
}
/* Fede spørgsmålstitler */
.magicfeedback-label {
font-weight: 700;
letter-spacing: -0.01em;
}
/* Pille-formet submit-knap */
.magicfeedback-submit {
border-radius: 9999px;
padding-inline: 1.5rem;
}
/* Kvadratiske emoji-ratings med blødt hover-lift */
.magicfeedback-rating-option-label-container img {
border-radius: 12px;
transition: transform 0.15s ease;
}
.magicfeedback-rating-option-label-container img:hover {
transform: translateY(-2px) scale(1.05);
}
/* Erstat matrix-striberne med kun border */
.magicfeedback-multi-question-matrix-row-tr:nth-child(even) {
background: transparent;
}
.magicfeedback-multi-question-matrix-table td,
.magicfeedback-multi-question-matrix-table th {
border-bottom: 1px solid var(--mf-border);
}

questionFormat skifter mellem de to indbyggede visuelle densiteter.

await form.generate("survey-root", {
questionFormat: "slim", // eller "standard" (default)
});
  • "standard" — generøs spacing, store inputs. Velegnet til full-page-undersøgelser.
  • "slim" — kompakt, passer i modaler, drawers eller sidebars.

addSuccessScreen tænder/slukker den indbyggede “tak”-visning. Kombiner med successMessage for at lokalisere, eller deaktivér den og render din egen:

await form.generate("survey-root", {
addSuccessScreen: false,
afterSubmitEvent: ({ completed }) => {
if (completed) {
renderMyOwnThankYouView();
}
},
});

Se Livscyklus-events for hele callback-overfladen.


Har du brug for en spørgsmålstype, et layout eller en adfærd SDK’et ikke eksponerer, så tal med din MagicFeedback-kontakt frem for at patche SDK’et i userland.