Developer-first,
open source
Typeform alternative

Forms.md lets you build powerful multi-step forms and surveys with minimal code. Create production-ready forms that are privacy-focused, accessible, localizable, and themeable. Perfect for user onboarding, data collection, customer feedback, and much more.

#! id = onboarding-form
#! post-url = /api/onboard

position* = ChoiceInput(
  | question = What's your position?
  | choices = Product Manager, Software Engineer, Founder, Other
)

::: [{$ position $}]
{% if position == "Other" %}
positionOther* = TextInput(
  | question = Other
  | labelStyle = classic
)
{% endif %}
:::

---
|> 50%

referralSource* = ChoiceInput(
  | question = How did you hear about us?
  | choices = News, Search Engine, Social Media, Recommendation
)

---
-> referralSource == "Recommendation"
|> 75%

recommender = EmailInput(
  | question = Who recommended you?
  | description = We may be able to reach out to them and provide a discount for helping us out.
)
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "onboarding-form",
  postUrl: "/api/onboard",
});
 
// Choice input for position
composer.choiceInput("position", {
  question: "What's your position?",
  choices: ["Product Manager", "Software Engineer", "Founder", "Other"],
  required: true,
});
 
// Text input if user selects "Other" position
composer.textInput("positionOther", {
  question: "Other",
  required: true,
  labelStyle: "classic",
  displayCondition: {
    dependencies: ["position"],
    condition: "position == 'Other'",
  },
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Choice input for how user discovered the product
composer.choiceInput("referralSource", {
  question: "How did you hear about us?",
  choices: ["News", "Search Engine", "Social Media", "Recommendation"],
  required: true,
});
 
// Start new slide, show only if user was recommended, progress indicator at 75%
composer.slide({
  jumpCondition: "referralSource == 'Recommendation'",
  pageProgress: "75%",
});
 
// Email input for recommender email address
composer.emailInput("recommender", {
  question: "Who recommended you?",
  description:
    "We may be able to reach out to them and provide a discount for helping us out.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("onboarding-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "onboarding-form",
  postUrl: "/api/onboard",
});
 
// Choice input for position
composer.choiceInput("position", {
  question: "What's your position?",
  choices: ["Product Manager", "Software Engineer", "Founder", "Other"],
  required: true,
});
 
// Text input if user selects "Other" position
composer.textInput("positionOther", {
  question: "Other",
  required: true,
  labelStyle: "classic",
  displayCondition: {
    dependencies: ["position"],
    condition: "position == 'Other'",
  },
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Choice input for how user discovered the product
composer.choiceInput("referralSource", {
  question: "How did you hear about us?",
  choices: ["News", "Search Engine", "Social Media", "Recommendation"],
  required: true,
});
 
// Start new slide, show only if user was recommended, progress indicator at 75%
composer.slide({
  jumpCondition: "referralSource == 'Recommendation'",
  pageProgress: "75%",
});
 
// Email input for recommender email address
composer.emailInput("recommender", {
  question: "Who recommended you?",
  description:
    "We may be able to reach out to them and provide a discount for helping us out.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("onboarding-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = onboarding-form
#! post-url = /api/onboard

position* = ChoiceInput(
  | question = What's your position?
  | choices = Product Manager, Software Engineer, Founder, Other
)

::: [{$ position $}]
{% if position == "Other" %}
positionOther* = TextInput(
  | question = Other
  | labelStyle = classic
)
{% endif %}
:::

---
|> 50%

referralSource* = ChoiceInput(
  | question = How did you hear about us?
  | choices = News, Search Engine, Social Media, Recommendation
)

---
-> referralSource == "Recommendation"
|> 75%

recommender = EmailInput(
  | question = Who recommended you?
  | description = We may be able to reach out to them and provide a discount for helping us out.
)
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("onboarding-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
Expand code Collapse code
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "onboarding-form",
  postUrl: "/api/onboard",
});
 
// Choice input for position
composer.choiceInput("position", {
  question: "What's your position?",
  choices: ["Product Manager", "Software Engineer", "Founder", "Other"],
  required: true,
});
 
// Text input if user selects "Other" position
composer.textInput("positionOther", {
  question: "Other",
  required: true,
  labelStyle: "classic",
  displayCondition: {
    dependencies: ["position"],
    condition: "position == 'Other'",
  },
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Choice input for how user discovered the product
composer.choiceInput("referralSource", {
  question: "How did you hear about us?",
  choices: ["News", "Search Engine", "Social Media", "Recommendation"],
  required: true,
});
 
// Start new slide, show only if user was recommended, progress indicator at 75%
composer.slide({
  jumpCondition: "referralSource == 'Recommendation'",
  pageProgress: "75%",
});
 
// Email input for recommender email address
composer.emailInput("recommender", {
  question: "Who recommended you?",
  description:
    "We may be able to reach out to them and provide a discount for helping us out.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("onboarding-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "onboarding-form",
  postUrl: "/api/onboard",
});
 
// Choice input for position
composer.choiceInput("position", {
  question: "What's your position?",
  choices: ["Product Manager", "Software Engineer", "Founder", "Other"],
  required: true,
});
 
// Text input if user selects "Other" position
composer.textInput("positionOther", {
  question: "Other",
  required: true,
  labelStyle: "classic",
  displayCondition: {
    dependencies: ["position"],
    condition: "position == 'Other'",
  },
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Choice input for how user discovered the product
composer.choiceInput("referralSource", {
  question: "How did you hear about us?",
  choices: ["News", "Search Engine", "Social Media", "Recommendation"],
  required: true,
});
 
// Start new slide, show only if user was recommended, progress indicator at 75%
composer.slide({
  jumpCondition: "referralSource == 'Recommendation'",
  pageProgress: "75%",
});
 
// Email input for recommender email address
composer.emailInput("recommender", {
  question: "Who recommended you?",
  description:
    "We may be able to reach out to them and provide a discount for helping us out.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("onboarding-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = onboarding-form
#! post-url = /api/onboard

position* = ChoiceInput(
  | question = What's your position?
  | choices = Product Manager, Software Engineer, Founder, Other
)

::: [{$ position $}]
{% if position == "Other" %}
positionOther* = TextInput(
  | question = Other
  | labelStyle = classic
)
{% endif %}
:::

---
|> 50%

referralSource* = ChoiceInput(
  | question = How did you hear about us?
  | choices = News, Search Engine, Social Media, Recommendation
)

---
-> referralSource == "Recommendation"
|> 75%

recommender = EmailInput(
  | question = Who recommended you?
  | description = We may be able to reach out to them and provide a discount for helping us out.
)
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("onboarding-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();

Features

Everything you need to create powerful forms and surveys, licensed under Apache-2.0.

Unlimited form responses

Collect as many responses as you want without any arbitary limits.

Multi-step forms

Create slides with progress indicators to show current step.

Logic jumps

Show or skip slides depending on what the user inputs.

Partial submissions

Slide-level (or partial) submissions to store data on every step.

Collect data of all types

Picture choice, rating, NPS®, date-time, file, etc., plus all basic types.

Data-binding

Display input values that automatically update when the value changes.

Fully customizable

Set the colors, font, and everything else to match your brand.

Localizable

Set localization and automatically translate your forms.

Google Sheets integration

Send your form responses directly to Google Sheets.

Spam protection

Use reCAPTCHA to protect against spam using the built-in integration.

Works with your tech stack

Works with projects written in JavaScript, TypeScript, React, Angular, Vue, Python, Django, etc.

Privacy-focused

No telemetry, the forms are created entirely on the client-side without any iframes. GDPR compliant by default.

Use case

Survey your customers

Collect meaningful feedback through ratings, opinion scales, and Net Promoter Scores®. Create simple, powerful forms that integrate seamlessly into your website or app—giving you the insights you need to grow.

#! id = customer-survey-form
#! post-url = /api/customer-survey

nps* = OpinionScale(
  | question = How likely are you to recommend our product to a friend or colleague?
)

---
-> nps >= 6
|> 50%

email = EmailInput(
  | question = Would you like to receive product updates?
  | description = If yes, please enter your email address. We only send high-quality updates and newsletters.
)
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "customer-survey-form",
  postUrl: "/api/customer-survey",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question:
    "How likely are you to recommend our product to a friend or colleague?",
  required: true,
});

// Start new slide, show only if NPS score is positive, progress indicator at 50%
composer.slide({
  jumpCondition: "nps >= 6",
  pageProgress: "50%",
});

// Email input for product updates
composer.emailInput("email", {
  question: "Would you like to receive product updates?",
  description:
    "If yes, please enter your email address. We only send high-quality updates and newsletters.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "customer-survey-form",
  postUrl: "/api/customer-survey",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question:
    "How likely are you to recommend our product to a friend or colleague?",
  required: true,
});

// Start new slide, show only if NPS score is positive, progress indicator at 50%
composer.slide({
  jumpCondition: "nps >= 6",
  pageProgress: "50%",
});

// Email input for product updates
composer.emailInput("email", {
  question: "Would you like to receive product updates?",
  description:
    "If yes, please enter your email address. We only send high-quality updates and newsletters.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = customer-survey-form
#! post-url = /api/customer-survey

nps* = OpinionScale(
  | question = How likely are you to recommend our product to a friend or colleague?
)

---
-> nps >= 6
|> 50%

email = EmailInput(
  | question = Would you like to receive product updates?
  | description = If yes, please enter your email address. We only send high-quality updates and newsletters.
)
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
Expand code Collapse code
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "customer-survey-form",
  postUrl: "/api/customer-survey",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question:
    "How likely are you to recommend our product to a friend or colleague?",
  required: true,
});

// Start new slide, show only if NPS score is positive, progress indicator at 50%
composer.slide({
  jumpCondition: "nps >= 6",
  pageProgress: "50%",
});

// Email input for product updates
composer.emailInput("email", {
  question: "Would you like to receive product updates?",
  description:
    "If yes, please enter your email address. We only send high-quality updates and newsletters.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "customer-survey-form",
  postUrl: "/api/customer-survey",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question:
    "How likely are you to recommend our product to a friend or colleague?",
  required: true,
});

// Start new slide, show only if NPS score is positive, progress indicator at 50%
composer.slide({
  jumpCondition: "nps >= 6",
  pageProgress: "50%",
});

// Email input for product updates
composer.emailInput("email", {
  question: "Would you like to receive product updates?",
  description:
    "If yes, please enter your email address. We only send high-quality updates and newsletters.",
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = customer-survey-form
#! post-url = /api/customer-survey

nps* = OpinionScale(
  | question = How likely are you to recommend our product to a friend or colleague?
)

---
-> nps >= 6
|> 50%

email = EmailInput(
  | question = Would you like to receive product updates?
  | description = If yes, please enter your email address. We only send high-quality updates and newsletters.
)
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
Use case

Collect employee feedback

Uncover what motivates your employees through engaging surveys that capture authentic feedback on workplace experiences, job satisfaction, and innovative ideas. Transform insights into action.

#! id = employee-feedback-form
#! post-url = /api/employee-feedback

rating* = RatingInput(
  | question = How satisfied are you with your current role?
)

---
|> 50%

feedback = TextInput(
  | question = Do you have any feedback to help us improve?
  | description = Share your thoughts on how we can make our company a better place for everyone.
  | multiline
)
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "employee-feedback-form",
  postUrl: "/api/employee-feedback",
});
 
// Rating input for satisfaction
composer.ratingInput("rating", {
  question: "How satisfied are you with your current role?",
  required: true,
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Multiline text input for feedback
composer.textInput("feedback", {
  question: "Do you have any feedback to help us improve?",
  description: "Share your thoughts on how we can make our company a better place for everyone.",
  multiline: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("employee-feedback-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "employee-feedback-form",
  postUrl: "/api/employee-feedback",
});
 
// Rating input for satisfaction
composer.ratingInput("rating", {
  question: "How satisfied are you with your current role?",
  required: true,
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Multiline text input for feedback
composer.textInput("feedback", {
  question: "Do you have any feedback to help us improve?",
  description: "Share your thoughts on how we can make our company a better place for everyone.",
  multiline: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("employee-feedback-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = employee-feedback-form
#! post-url = /api/employee-feedback

rating* = RatingInput(
  | question = How satisfied are you with your current role?
)

---
|> 50%

feedback = TextInput(
  | question = Do you have any feedback to help us improve?
  | description = Share your thoughts on how we can make our company a better place for everyone.
  | multiline
)

`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("employee-feedback-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
Expand code Collapse code
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "employee-feedback-form",
  postUrl: "/api/employee-feedback",
});
 
// Rating input for satisfaction
composer.ratingInput("rating", {
  question: "How satisfied are you with your current role?",
  required: true,
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Multiline text input for feedback
composer.textInput("feedback", {
  question: "Do you have any feedback to help us improve?",
  description: "Share your thoughts on how we can make our company a better place for everyone.",
  multiline: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("employee-feedback-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "employee-feedback-form",
  postUrl: "/api/employee-feedback",
});
 
// Rating input for satisfaction
composer.ratingInput("rating", {
  question: "How satisfied are you with your current role?",
  required: true,
});
 
// Start new slide, progress indicator at 50%
composer.slide({
  pageProgress: "50%",
});
 
// Multiline text input for feedback
composer.textInput("feedback", {
  question: "Do you have any feedback to help us improve?",
  description: "Share your thoughts on how we can make our company a better place for everyone.",
  multiline: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("employee-feedback-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = employee-feedback-form
#! post-url = /api/employee-feedback

rating* = RatingInput(
  | question = How satisfied are you with your current role?
)

---
|> 50%

feedback = TextInput(
  | question = Do you have any feedback to help us improve?
  | description = Share your thoughts on how we can make our company a better place for everyone.
  | multiline
)

`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("employee-feedback-form-container"),
  {
    postHeaders: {
      Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
  },
);
formsmd.init();
Use case

Mailing list sign up

Grow your subscriber count with beautifully designed forms that turn visitors into loyal followers. Create delightful email capture forms that consistently drive high conversion rates.

#! id = mailing-list-form
#! post-url = /api/mailing-list

email* = EmailInput(
  | question = Join our mailing list
  | description = Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.
)

---
-> end

# [.text-center] Thank you

[.text-center style="font-size: 18px;"]
Subscribed to mailing list with {$ email $}.
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "mailing-list-form",
  postUrl: "/api/mailing-list",
});

// Email input
composer.emailInput("email", {
  question: "Join our mailing list",
  description:
    "Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.",
  required: true,
});

// End slide with custom message and data-binding
composer.endSlide();
composer.h1("Thank you", {
  classNames: ["text-center"],
});
composer.p("Subscribed to mailing list with {$ email $}.", {
  classNames: ["text-center"],
  attrs: [
    {
      name: "style",
      value: "font-size: 18px;",
    },
  ],
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("mailing-list-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "mailing-list-form",
  postUrl: "/api/mailing-list",
});

// Email input
composer.emailInput("email", {
  question: "Join our mailing list",
  description:
    "Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.",
  required: true,
});

// End slide with custom message and data-binding
composer.endSlide();
composer.h1("Thank you", {
  classNames: ["text-center"],
});
composer.p("Subscribed to mailing list with {$ email $}.", {
  classNames: ["text-center"],
  attrs: [
    {
      name: "style",
      value: "font-size: 18px;",
    },
  ],
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("mailing-list-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = mailing-list-form
#! post-url = /api/mailing-list

email* = EmailInput(
  | question = Join our mailing list
  | description = Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.
)

---
-> end

# [.text-center] Thank you

[.text-center style="font-size: 18px;"]
Subscribed to mailing list with {$ email $}.
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("mailing-list-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
Expand code Collapse code
import { Composer, Formsmd } from "formsmd";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "mailing-list-form",
  postUrl: "/api/mailing-list",
});

// Email input
composer.emailInput("email", {
  question: "Join our mailing list",
  description:
    "Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.",
  required: true,
});

// End slide with custom message and data-binding
composer.endSlide();
composer.h1("Thank you", {
  classNames: ["text-center"],
});
composer.p("Subscribed to mailing list with {$ email $}.", {
  classNames: ["text-center"],
  attrs: [
    {
      name: "style",
      value: "font-size: 18px;",
    },
  ],
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("mailing-list-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID and submission endpoint
const composer = new Composer({
  id: "mailing-list-form",
  postUrl: "/api/mailing-list",
});

// Email input
composer.emailInput("email", {
  question: "Join our mailing list",
  description:
    "Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.",
  required: true,
});

// End slide with custom message and data-binding
composer.endSlide();
composer.h1("Thank you", {
  classNames: ["text-center"],
});
composer.p("Subscribed to mailing list with {$ email $}.", {
  classNames: ["text-center"],
  attrs: [
    {
      name: "style",
      value: "font-size: 18px;",
    },
  ],
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("mailing-list-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = mailing-list-form
#! post-url = /api/mailing-list

email* = EmailInput(
  | question = Join our mailing list
  | description = Stay informed of every update that matters - we'll deliver the latest news straight to your inbox.
)

---
-> end

# [.text-center] Thank you

[.text-center style="font-size: 18px;"]
Subscribed to mailing list with {$ email $}.
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("mailing-list-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
Use case

Simple job posts in minutes

Create simple job posts directly on your website or app. No need to pay for expensive recruiting platforms until you actually need them.

#! form-style = classic
#! id = job-post-form
#! page-progress = hide
#! placeholders = hide
#! post-url = /api/apply
#! submit-button-text = Apply

[.col-6]
fullName* = TextInput(
  | question = Full name
)

[.col-6]
email* = EmailInput(
  | question = Email
)

cv* = FileInput(
  | question = CV
)
import { Composer, Formsmd } from "formsmd";

// Create form with ID, form styles, and submission endpoint
const composer = new Composer({
  formStyle: "classic",
  id: "job-post-form",
  pageProgress: "hide",
  placeholders: "hide",
  postUrl: "/api/apply",
  submitButtonText: "Apply",
});

// Text input for full name
composer.textInput("fullName", {
  question: "Full name",
  required: true,
  classNames: ["col-6"],
});

// Email input for email address
composer.emailInput("email", {
  question: "Email",
  required: true,
  classNames: ["col-6"],
});

// File input for CV
composer.fileInput("cv", {
  question: "CV",
  required: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("job-post-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID, form styles, and submission endpoint
const composer = new Composer({
  formStyle: "classic",
  id: "job-post-form",
  pageProgress: "hide",
  placeholders: "hide",
  postUrl: "/api/apply",
  submitButtonText: "Apply",
});

// Text input for full name
composer.textInput("fullName", {
  question: "Full name",
  required: true,
  classNames: ["col-6"],
});

// Email input for email address
composer.emailInput("email", {
  question: "Email",
  required: true,
  classNames: ["col-6"],
});

// File input for CV
composer.fileInput("cv", {
  question: "CV",
  required: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("job-post-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! form-style = classic
#! id = job-post-form
#! page-progress = hide
#! placeholders = hide
#! post-url = /api/apply
#! submit-button-text = Apply

[.col-6]
fullName* = TextInput(
  | question = Full name
)

[.col-6]
email* = EmailInput(
  | question = Email
)

cv* = FileInput(
  | question = CV
)
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("job-post-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
Expand code Collapse code
import { Composer, Formsmd } from "formsmd";

// Create form with ID, form styles, and submission endpoint
const composer = new Composer({
  formStyle: "classic",
  id: "job-post-form",
  pageProgress: "hide",
  placeholders: "hide",
  postUrl: "/api/apply",
  submitButtonText: "Apply",
});

// Text input for full name
composer.textInput("fullName", {
  question: "Full name",
  required: true,
  classNames: ["col-6"],
});

// Email input for email address
composer.emailInput("email", {
  question: "Email",
  required: true,
  classNames: ["col-6"],
});

// File input for CV
composer.fileInput("cv", {
  question: "CV",
  required: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("job-post-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID, form styles, and submission endpoint
const composer = new Composer({
  formStyle: "classic",
  id: "job-post-form",
  pageProgress: "hide",
  placeholders: "hide",
  postUrl: "/api/apply",
  submitButtonText: "Apply",
});

// Text input for full name
composer.textInput("fullName", {
  question: "Full name",
  required: true,
  classNames: ["col-6"],
});

// Email input for email address
composer.emailInput("email", {
  question: "Email",
  required: true,
  classNames: ["col-6"],
});

// File input for CV
composer.fileInput("cv", {
  question: "CV",
  required: true,
});

// Initialize with template, container, and options
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("job-post-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! form-style = classic
#! id = job-post-form
#! page-progress = hide
#! placeholders = hide
#! post-url = /api/apply
#! submit-button-text = Apply

[.col-6]
fullName* = TextInput(
  | question = Full name
)

[.col-6]
email* = EmailInput(
  | question = Email
)

cv* = FileInput(
  | question = CV
)
`;

// Initialize with template, container, and options
const formsmd = new Formsmd(
  template,
  document.getElementById("job-post-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
  },
);
formsmd.init();
Feature

Translate, customize, and make it entirely yours

Change the localization setting to automatically translate your forms. Easily set the colors, font, and everything else to match your brand, seamlessly blending in the forms on your website or app. There's also a handy translate({...}) function that lets you define your translations directly in the form composer for dynamic localization.

#! id = ja-customer-survey-form
#! localization = ja
#! post-url = /api/customer-survey
#! rounded = none

nps* = OpinionScale(
  | question = 当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?
)
import { Composer, Formsmd } from "formsmd";

// Create form with ID, localization, submission endpoint, and border radius
const composer = new Composer({
  id: "ja-customer-survey-form",
  localization: "ja",
  postUrl: "/api/customer-survey",
  rounded: "none",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question: "当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?",
  required: true,
});

// Initialize with template, container, and options with theming
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("ja-customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
    themeDark: {
      accent: "#dfdfdf",
    },
    themeLight: {
      accent: "rgb(26, 26, 26)",
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID, localization, submission endpoint, and border radius
const composer = new Composer({
  id: "ja-customer-survey-form",
  localization: "ja",
  postUrl: "/api/customer-survey",
  rounded: "none",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question: "当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?",
  required: true,
});

// Initialize with template, container, and options with theming
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("ja-customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
    themeDark: {
      accent: "#dfdfdf",
    },
    themeLight: {
      accent: "rgb(26, 26, 26)",
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = ja-customer-survey-form
#! localization = ja
#! post-url = /api/customer-survey
#! rounded = none

nps* = OpinionScale(
  | question = 当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?
)
`;

// Initialize with template, container, and options with theming
const formsmd = new Formsmd(
  template,
  document.getElementById("ja-customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
    themeDark: {
      accent: "#dfdfdf",
    },
    themeLight: {
      accent: "rgb(26, 26, 26)",
    },
  },
);
formsmd.init();
Expand code Collapse code
import { Composer, Formsmd } from "formsmd";

// Create form with ID, localization, submission endpoint, and border radius
const composer = new Composer({
  id: "ja-customer-survey-form",
  localization: "ja",
  postUrl: "/api/customer-survey",
  rounded: "none",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question: "当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?",
  required: true,
});

// Initialize with template, container, and options with theming
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("ja-customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
    themeDark: {
      accent: "#dfdfdf",
    },
    themeLight: {
      accent: "rgb(26, 26, 26)",
    },
  },
);
formsmd.init();
import { Composer } from "formsmd";
import { FormsmdComponent } from "formsmd-react";

// Create form with ID, localization, submission endpoint, and border radius
const composer = new Composer({
  id: "ja-customer-survey-form",
  localization: "ja",
  postUrl: "/api/customer-survey",
  rounded: "none",
});

// Net Promoter Score®
composer.opinionScale("nps", {
  question: "当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?",
  required: true,
});

// Initialize with template, container, and options with theming
const formsmd = new Formsmd(
  composer.template,
  document.getElementById("ja-customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
    themeDark: {
      accent: "#dfdfdf",
    },
    themeLight: {
      accent: "rgb(26, 26, 26)",
    },
  },
);
formsmd.init();
import { Formsmd } from "formsmd";

// Create template
const template = `
#! id = ja-customer-survey-form
#! localization = ja
#! post-url = /api/customer-survey
#! rounded = none

nps* = OpinionScale(
  | question = 当社の製品を友人や同僚に推薦する可能性はどの程度ありますか?
)
`;

// Initialize with template, container, and options with theming
const formsmd = new Formsmd(
  template,
  document.getElementById("ja-customer-survey-form-container"),
  {
    postHeaders: {
      Authorization: "Basic <API_KEY>",
    },
    themeDark: {
      accent: "#dfdfdf",
    },
    themeLight: {
      accent: "rgb(26, 26, 26)",
    },
  },
);
formsmd.init();
80% cheaper

Save big with Forms.md!

All features on Forms.md are completely free without any arbitary usage limits. You only need to pay to remove the branding on the forms. Our Pro version delivers enterprise-level functionality at a fraction of the cost. In fact, for 10,000 monthly responses, you'll save over $750 annually compared to Typeform!

Free
Branded forms
$0
Free forever
  • Yes: 1 end product
  • Yes: All features available
  • Yes: Use for personal or client
  • Yes: Unlimited form responses
  • No: Email/chat support
  • No: Remove Forms.md branding
Pro
Remove branding
$20/month
Tax inclusive
Save $60
$25/month
Tax inclusive
  • Yes: 1 end product
  • Yes: All features available
  • Yes: Use for personal or client
  • Yes: Unlimited form responses
  • Yes: Email/chat support
  • Yes: Remove Forms.md branding
Enterprise
For large organizations
Contact for pricing
  • Yes: Everything in Pro
  • Yes: Dedicated support
  • Yes: Custom features upon request
  • Yes: Custom integrations upon request
  • Yes: And much more

More features coming soon, such as AI form builder, form backend, payments, integrations, etc. For questions or queries, please contact us or book a call.