pmf widget: add focus trap, make radio buttons accesible via keyboard

This commit is contained in:
Matthias Nannt
2023-01-30 11:58:46 +01:00
parent 58e643bac5
commit 6c85188d4d
6 changed files with 101 additions and 52 deletions
-2
View File
@@ -17,14 +17,12 @@
"clean": "rm -rf dist"
},
"devDependencies": {
"@floating-ui/dom": "^1.1.0",
"@formbricks/tsconfig": "workspace:*",
"eslint": "^8.32.0",
"eslint-config-formbricks": "workspace:*",
"focus-trap": "^7.2.0",
"html-minifier": "^4.0.0",
"microbundle": "^0.15.1",
"tsup": "^6.4.0",
"typescript": "^4.9.4"
}
}
File diff suppressed because one or more lines are too long
+11 -1
View File
@@ -95,6 +95,10 @@
transition: all 0.3s ease-out;
}
.formbricks-next-button:focus {
box-shadow: 0 0 0 3px var(--formbricksPmf-brand-color-transparent);
}
/* Textarea */
.formbricks-textarea {
@@ -130,7 +134,9 @@
}
.formbricks-radio-input {
display: none;
width: 0;
position: fixed;
opacity: 0;
}
.formbricks-radio-label {
@@ -150,6 +156,10 @@
background-color: var(--formbricksPmf-brand-color);
}
.formbricks-radio-input:focus + .formbricks-radio-label {
box-shadow: 0 0 0 3px var(--formbricksPmf-brand-color-transparent);
}
.formbricks-radio-input:checked + label {
background-color: #58ba83;
}
+75 -45
View File
@@ -7,26 +7,35 @@
<fieldset class="formbricks-radio-fieldset">
<legend class="formbricks-sr-only">Disappointment options</legend>
<div class="formbricks-radio-options">
<div
class="formbricks-radio-option"
data-element-name="disappointment"
data-element-value="veryDisappointed">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">very disappointed </label>
<div class="formbricks-radio-option">
<input
id="formbricksPmf-0-0"
name="formbricksPmf-0-0"
type="radio"
class="formbricks-radio-input"
data-element-name="disappointment"
data-element-value="veryDisappointed" />
<label class="formbricks-radio-label" for="formbricksPmf-0-0">very disappointed </label>
</div>
<div
class="formbricks-radio-option"
data-element-name="disappointment"
data-element-value="somewhatDisappointed">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">somewhat disappointed </label>
<div class="formbricks-radio-option">
<input
id="formbricksPmf-0-1"
name="formbricksPmf-0-1"
type="radio"
class="formbricks-radio-input"
data-element-name="disappointment"
data-element-value="somewhatDisappointed" />
<label class="formbricks-radio-label" for="formbricksPmf-0-1">somewhat disappointed </label>
</div>
<div
class="formbricks-radio-option"
data-element-name="disappointment"
data-element-value="notDisappointed">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">not disappointed </label>
<div class="formbricks-radio-option">
<input
id="formbricksPmf-0-2"
name="formbricksPmf-0-2"
type="radio"
class="formbricks-radio-input"
data-element-name="disappointment"
data-element-value="notDisappointed" />
<label class="formbricks-radio-label" for="formbricksPmf-0-2">not disappointed </label>
</div>
</div>
</fieldset>
@@ -35,7 +44,7 @@
<div class="formbricks-element formbricks-hidden" id="formbricks-question-1">
<p class="formbricks-element-label">What is the main benefit you receive from our service?</p>
<form class="formbricks-form" data-element-name="mainBenefit">
<textarea rows="4" name="mainBenefit" class="formbricks-textarea" required></textarea>
<textarea rows="4" name="mainBenefit" class="formbricks-textarea" required autofocus></textarea>
<div class="formbricks-next-button-wrapper">
<button type="submit" class="formbricks-next-button">Next</button>
</div>
@@ -47,34 +56,55 @@
<fieldset class="formbricks-radio-fieldset">
<legend class="formbricks-sr-only">Job title options</legend>
<div class="formbricks-radio-options">
<div class="formbricks-radio-option" data-element-name="userSegment" data-element-value="founder">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">Founder</label>
<div class="formbricks-radio-option">
<input
data-element-name="userSegment"
data-element-value="founder"
id="formbricksPmf-2-0"
name="formbricksPmf-2-0"
type="radio"
class="formbricks-radio-input" />
<label class="formbricks-radio-label" for="formbricksPmf-2-0">Founder</label>
</div>
<div class="formbricks-radio-option" data-element-name="userSegment" data-element-value="executive">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">Executive</label>
<div class="formbricks-radio-option">
<input
data-element-name="userSegment"
data-element-value="executive"
id="formbricksPmf-2-1"
name="formbricksPmf-2-1"
type="radio"
class="formbricks-radio-input" />
<label class="formbricks-radio-label" id="formbricksPmf-2-1">Executive</label>
</div>
<div
class="formbricks-radio-option"
data-element-name="userSegment"
data-element-value="productManager">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">Product Manager</label>
<div class="formbricks-radio-option">
<input
data-element-name="userSegment"
data-element-value="productManager"
id="formbricksPmf-2-2"
name="formbricksPmf-2-2"
type="radio"
class="formbricks-radio-input" />
<label class="formbricks-radio-label" id="formbricksPmf-2-2">Product Manager</label>
</div>
<div
class="formbricks-radio-option"
data-element-name="userSegment"
data-element-value="productOwner">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">Product Owner</label>
<div class="formbricks-radio-option">
<input
data-element-name="userSegment"
data-element-value="productOwner"
id="formbricksPmf-2-3"
name="formbricksPmf-2-3"
type="radio"
class="formbricks-radio-input" />
<label class="formbricks-radio-label" id="formbricksPmf-2-3">Product Owner</label>
</div>
<div
class="formbricks-radio-option"
data-element-name="userSegment"
data-element-value="softwareEngineer">
<input name="notification-method" type="radio" class="formbricks-radio-input" />
<label class="formbricks-radio-label">Software Engineer</label>
<div class="formbricks-radio-option">
<input
data-element-name="userSegment"
data-element-value="softwareEngineer"
id="formbricksPmf-2-4"
name="formbricksPmf-2-4"
type="radio"
class="formbricks-radio-input" />
<label class="formbricks-radio-label" id="formbricksPmf-2-4">Software Engineer</label>
</div>
</div>
</fieldset>
@@ -83,7 +113,7 @@
<div class="formbricks-element formbricks-hidden" id="formbricks-question-3">
<p class="formbricks-element-label">How can we improve our service for you?</p>
<form class="formbricks-form" data-element-name="improvement">
<textarea rows="4" name="improvement" class="formbricks-textarea" required></textarea>
<textarea rows="4" name="improvement" class="formbricks-textarea" required autofocus></textarea>
<div class="formbricks-next-button-wrapper">
<button type="submit" class="formbricks-next-button">Next</button>
</div>
@@ -93,7 +123,7 @@
<div class="formbricks-element formbricks-hidden" id="formbricks-question-4">
<p class="formbricks-element-label">What type of people would benefit most from using our service?</p>
<form class="formbricks-form" data-element-name="selfSegmentation">
<textarea rows="4" name="selfSegmentation" class="formbricks-textarea" required></textarea>
<textarea rows="4" name="selfSegmentation" class="formbricks-textarea" required autofocus></textarea>
<div class="formbricks-next-button-wrapper">
<button type="submit" class="formbricks-next-button">Submit</button>
</div>
+11 -1
View File
@@ -1,3 +1,4 @@
import { createFocusTrap } from "focus-trap";
import { formHtml } from "./form-html";
import formCss from "./form.css";
@@ -27,6 +28,11 @@ window.addEventListener("load", init);
const formContainer = document.createElement("div");
formContainer.id = "formbricks-container";
const trap = createFocusTrap(formContainer, {
initialFocus: "#formbricksPmf-0-0",
allowOutsideClick: true,
});
function init() {
// add css to head
if (document.getElementById("formbricksPmf__css") === null) {
@@ -49,9 +55,12 @@ function init() {
// add listeners
// radio buttons
Array.from(
formContainer.getElementsByClassName("formbricks-radio-option") as HTMLCollectionOf<HTMLElement>
formContainer.getElementsByClassName("formbricks-radio-input") as HTMLCollectionOf<HTMLElement>
).forEach((el) => {
el.addEventListener("click", () => submitElement(el.dataset?.elementName, el.dataset?.elementValue));
el.addEventListener("keypress", function (e) {
if (e.key === "Enter") return submitElement(el.dataset?.elementName, el.dataset?.elementValue);
});
});
// text inputs
Array.from(
@@ -63,6 +72,7 @@ function init() {
submitElement(el.dataset?.elementName, e.target.elements[el.dataset?.elementName].value);
};
});
trap.activate();
sendWarmupRequest();
}
+3 -2
View File
@@ -4,8 +4,8 @@
window.formbricksPmf = {
...window.formbricksPmf,
config: {
formbricksUrl: "https://app.formbricks.com",
formId: "cldekteoj0000nr0gjlvp34ny",
formbricksUrl: "http://localhost:3000",
formId: "cldbru2nu000s19t6mtc4bhk4",
containerId: "test-div",
contact: {
name: "Peer",
@@ -31,4 +31,5 @@
</head>
<body style="background-color: #ccc">
<div id="test-div" style="background-color: #fff; width: 40rem; height: 30rem"></div>
<button>Test</button>
</body>