JavaScript
Drop the Issued script into any HTML page. The widget renders into a container you provide and posts submissions to your project.
Install
No package to install — reference the hosted script directly.
<script src="https://issued.dev/widget/issued.js"></script>Minimal embed
Render a container, then call Issued.init(...) with your project ID. Copy your real project ID from the Embed Code page in the dashboard.
<div id="issued-widget-container"></div>
<script src="https://issued.dev/widget/issued.js"></script>
<script>
Issued.init({
projectId: "your-project-id",
fields: {
subject: { visible: true, required: true, label: "Subject" },
description: { visible: true, required: true, label: "Description" },
email: { visible: true, required: false, label: "Email" }
}
});
</script>Hidden metadata
Pass fields with visible: false and a value to attach context (user ID, plan tier, app version, page URL) to every issue automatically.
Issued.init({
projectId: "your-project-id",
fields: {
subject: { visible: true, required: true },
description: { visible: true, required: true },
email: { visible: false, value: currentUser.email },
userId: { visible: false, value: currentUser.id },
pageUrl: { visible: false, value: window.location.href },
appVersion: { visible: false, value: "2.4.1" }
}
});The full list of built-in fields (and the provider-specific ones like github_labels and linear_labels) lives in the fields reference.
Styling
Pass a theme object to match your brand. Full property list in the styling guide.
Issued.init({
projectId: "your-project-id",
fields: { /* ... */ },
theme: {
mode: "auto", // "auto" | "light" | "dark"
primaryColor: "#6366f1",
errorColor: "#dc2626",
successColor: "#059669",
borderRadius: "8px",
fontFamily: "Inter, sans-serif"
}
});Callbacks
Hook into the submission lifecycle — gate submissions, toast on success, or capture validation errors for analytics.
Issued.init({
projectId: "your-project-id",
fields: { /* ... */ },
callbacks: {
onBeforeSubmit: (formData) => {
// Return false to cancel the submission.
return agreeToTerms();
},
onSuccess: ({ ticketId }) => {
console.log("Submitted:", ticketId);
},
onError: (err) => {
console.error(err);
},
onValidationError: (errors) => {
// { subject: ["Subject is required"], ... }
}
}
});See every callback signature in the callbacks reference.
Gotchas
- The container element must exist in the DOM before
Issued.init(...)runs. If you call it from a dynamically mounted component, ensure the container is rendered first. - Your page's origin must be in the project's whitelisted domains or submissions will be rejected with a
403 INVALID_ORIGIN. Toggle localhost access on in project settings while developing. - The default container ID is
issued-widget-container. Passcontainer: "#my-id"to target a different element.