Introduction

This documentation is made to support the Vue Flow Form open-source project - to help users and to encourage contributors. Documentation includes the latest project info, examples, and how-to's.

Vue Flow Form is a form generator Vue component, built as a lightweight solution with minimum dependencies. Create reactive, dynamic, and highly extensible forms with various field types, step-by-step interface, and conditional-logic. You can customize the appearance with slots and CSS variables.

Installation

Creating a form

  • To create a new form, import the necessary components and classes into your app, in a way that depends on the installation method and version of Vue Flow Form.
  • Add the component to your template and register it either locally or globally.
  • Define the form steps by passing the question options into QuestionModel class instances. Create as many QuestionModel instances as you like for your project by adding them inside the questions array in the data function.
  • Include the pre-built theme file or your own custom theme into your application #↓
  • Add language model as language prop (optional) and define it by creating a new instance of LanguageModel and setting its properties. #↓
  • Add submit and/or complete event listeners if you want to submit data to the backend.

When using npm

  • Import the FlowForm component itself, the QuestionModel class and QuestionType enum. If you're going to use the MultipleChoice or Dropdown field type, import the ChoiceOption class
    // import from npm package
    import { FlowForm, QuestionModel, QuestionType, ChoiceOption, LanguageModel, MatrixRow, MatrixColumn } from '@ditdot-dev/vue-flow-form';
    // import from npm package
    import FlowForm, { QuestionModel, QuestionType, ChoiceOption, LanguageModel } from '@ditdot-dev/vue-flow-form@1.1.7';
  • Add FlowForm component with the question list as questions prop
  • Define questions in the questions array
  • Import base CSS and optional theme CSS #↓

When using CDN

  • Vue Flow Form requires:
    • at least Vue version 3.x for Vue Flow Form v2.x or later
    • at least Vue version 2.6.x for Vue Flow Form v1.1.7
  • You can use the latest version, or any specific version including the Vue 2 compatible build:
    <script src="https://unpkg.com/@ditdot-dev/vue-flow-form@2.3.2"></script>
    <script src="https://unpkg.com/@ditdot-dev/vue-flow-form@1.1.7"></script>
  • Usage with plain JavaScript via CDN:
  • Import Vue.js, FlowForm in either the head or before closing the body of your HTML document
  • Import base CSS and theme CSS (optional) in the head of your HTML document #↓
  • Create new Vue instance in your app.js and add the questions array with QuestionModel instances
  • Make sure to register all components locally when using Vue 3

Question types

  • Text - QuestionType.Text
  • LongText (Textarea) - QuestionType.LongText
  • Number - QuestionType.Number
  • Email - QuestionType.Email
  • Phone - QuestionType.Phone
  • URL - QuestionType.Url
  • Password - QuestionType.Password
  • Date - QuestionType.Date
    • A native input type="date" datepicker
    • Browsers that don't natively support it (like Safari) will fall back to a text input. You can use the placeholder attribute to describe the expected date format
    • Alternatively, you can create a date input field by adding mask and placeholder attributes to QuestionType.Phone
      import { MaskPresets } from '@ditdot-dev/vue-flow-form';
      
      new QuestionModel({
        type: QuestionType.Phone,
        // use one of the MaskPresets constants or create your own - https://vuejs-tips.github.io/vue-the-mask/#tokens
        mask: MaskPresets.Date,
        placeholder: 'yyyy-mm-dd'
        // ...
      });
  • Dropdown (Select) - QuestionType.Dropdown
  • MultipleChoice - QuestionType.MultipleChoice
  • MultiplePictureChoice - QuestionType.MultiplePictureChoice
  • OpinionScale - QuestionType.OpinionScale
  • IconRate - QuestionType.IconRate
  • File - QuestionType.File
  • Matrix - QuestionType.Matrix
  • SectionBreak - QuestionType.SectionBreak

Defining questions

  • To define a question, create a new instance of QuestionModel and pass in the options
    new QuestionModel({
      id: 'path_b',
      tagline: 'Path B',
      title: 'Hmm, are you sure?',
      subtitle: 'Path A sounds like a winner! 😉',
      type: QuestionType.MultipleChoice,
      multiple: false,
      required: true,
      options: [
        new ChoiceOption({
          label: 'Ok, let\'s go with A',
          value: 'path_a'
        }),
        new ChoiceOption({
          label: 'Yes, finish the survey'
        })
      ],
      jump: {
        path_a: 'path_a'
      }
    })

Global options

  • type - (one of QuestionType constants above)
  • id - ID of the question (optional but necessary when using jump)
  • title - main title
  • tagline - text above question (optional)
  • subtitle - text below question (optional)
  • description - helper text below main content (optional)
  • descriptionLink - add links below main content (optional):
    descriptionLink: [
      new LinkOption({
        url: 'https://www.example.com',
        text: 'Example link', // optional, default is link url
        target: '_self' // optional, default is '_blank'
      })
    ]
    • if description text is defined, links will be added to the end of the description text
  • required - is field required or not (true/false - default is false)
    • turn on/off the required asterisk indicator next to the question in vue-flow-form/src/assets/css/common.css:
      .f-required {
        display: inline; /* or display: none; to turn off */
      }
  • answer - holds the user's answer after replying to a question. This can for example be used to pre-fill the answer to any of the questions.
  • jump - define which question to jump to after answering (function or object)
    • function: it will get the question model as the only parameter and must return the ID to jump to
    • object: must define object with possible answer values and jump IDs, eg.:
      {
        a: 'jump_a',
        b: 'jump_b',
        c: '_submit',
        _other: 'jump_other'
      }
    • Object key _other will be used when no other keys match the answer. Object value _submit will jump to form submit button
  • progressbar You can disable the progress bar (UX recommendation if you have many logic jumps) by passing false to the progressbar prop on the FlowForm component instance:
    <flow-form v-bind:progressbar="false"> <!-- ... --> </flow-form>
  • navigation You can disable the footer backward/forward navigation and Shift + Tab backward navigation by passing false to the navigation prop on the FlowForm component instance:
    <flow-form v-bind:navigation="false"> <!-- ... --> </flow-form>
  • timer Timer option is available by passing true to the timer prop on the FlowForm component instance. By default, the timer starts on the first step and ends on submit. Start and stop steps can be changed by passing the question ID to the timerStartStep and/or timerStopStep props:
    <flow-form v-bind:timer="true" timer-start-step="id_1" timer-stop-step="id_2"> <!-- ... --> </flow-form>

Question specific options

  • content - used only with SectionBreak (optional)
  • options - ChoiceOption array (used only with Dropdown and MultipleChoice)
    • ChoiceOption must have a label defined (this is what will be shown to the user)
    • if value is not defined, label will be used
  • inline - displays the field next to the question, used only with Dropdown (true/false - default is false)
  • placeholder - define custom placeholder for the input fields
    • if not defined, the default value from LanguageModel will be used
  • mask - input mask, used with Text, Email, Phone, Password and Number (optional)
  • maxLength - defines the maximum number of characters the user can enter into a Text, LongText, Number, Url, Phone, Password, Email or Date field
  • min and max - specifies the minimum and maximum value, when used with Date (in "yyyy-mm-dd" format) or Number. Defines the minimum and maximum number of uploaded files, when used with File (only when multiple is set to true). max is also used to set the number of options for the OpinionScale and IconRate questions
  • labelLeft and labelRight - used only with OpinionScale to add labels to the left and right of the number scale
  • helpText - help text, used only with LongText and MultipleChoice (optional)
    • if not defined, the default values from LanguageModel will be used
  • helpTextShow - shows help text, used with LongText and MultipleChoice (true/false - default is true)
  • multiple - when used with MultipleChoice, MultiplePictureChoice or Matrix, defines if multiple answers can be chosen (true/false - default is false). Used with File, allows more than one file to be selected (true/false - default is false)
  • allowOther - used only with MultipleChoice, adds custom text field to the MultipleChoice selection (true/false - default is false)
  • nextStepOnAnswer - used with MultipleChoice and MultiplePictureChoice (only when multiple is set to false), OpinionScale and IconRate; takes you to the next step after selecting an option (true/false - default is false)
  • imageSrc - used only with MultiplePictureChoice, adds image to the MultiplePictureChoice option
  • imageAlt - used only with MultiplePictureChoice, adds alt text to the MultiplePictureChoice option image
  • accept - used only with File, defines the file types the input should accept - MDN documentation
  • maxSize - used only with File, defines the maximum overall size of all uploaded files, in bytes
  • rows - add question rows to Matrix:
    rows: [
      new MatrixRow({
        id: 'experience',
        label: 'Rate your overall experience with our product'
      }),
      new MatrixRow({
        id: 'documentation',
        label: 'Rate your overall experience with our documentation'
      })
    ]
  • columns - add column options to Matrix:
    columns: [
      new MatrixColumn({
        value: '1',
        label: 'Very satisfied'
      }),
      new MatrixColumn({
        value: '2',
        label: 'Satisfied'
      })
    ]

For additional guidance, check the Questionnaire or other examples to see all question types defined.

Questions as components

  • This feature allows dynamic questions and Vue's conditional rendering, just make sure to define a unique ID for each question. Example usage:
    <template>
      <flow-form>
        <question id="name" type="text" title="Hello, what is your name?" v-model="name"></question>
        <question id="age" type="number" title="What is your age?" v-model="age"></question>
        <!-- name and age are stored in the FlowForm component's data and can be used in the following question -->
        <question v-if="age < 18" id="ageLimit" type="sectionbreak" title="Sorry, you are under 18"></question>
        <question v-else type="sectionbreak" id="greeting" :title="'Nice to meet you, ' + name + '. Welcome to our site!'"></question>
      </flow-form>
    </template>
    
    <script>
      import FlowForm from '../../src/components/FlowForm.vue'
      import Question from '../../src/components/Question.vue'
      // If using the npm package, use the following line instead of the ones above.
      // import { FlowForm, Question } from '@ditdot-dev/vue-flow-form'
    
      export default {
        name: 'example',
        components: {
          FlowForm,
          Question
        },
        data() {
          return {
            name: '',
            age: ''
          }
        }
      }
    </script>
  • When using CDN, make sure to register the Question component locally:
    export default {
      name: 'example',
      components: {
        question: VueFlowForm.Question
      },
      ...
    }
    export default {
      name: 'example',
      components: {
        question: FlowForm.Question
      },
      ...
    }

Public API functions

  • reset - resets all the answers and returns to the first question.
  • goToQuestion, goToPreviousQuestion, goToNextQuestion - API functions which let you go to a specific question. Note: Allowed only if application logic allows it, to avoid skipping required questions that weren't already answered.
  • You can use API function by storing a ref to Flow Form in your parent component and calling it, eg.:
    mounted() {
        this.$refs.flowform.goToQuestion(3)
        // You can also jump by question ID:
        // this.$refs.flowform.goToQuestion('question_id')
    }

FlowForm component events

  • complete - emitted whenever the "completed" status changes, the first parameter is the status, the second is the question list, eg.:
    function onComplete(completed, questionList) {
      // Handle status change.
    }
  • If the user completes the form, then goes back and changes any of the answers to make them invalid, this event will again be called with false as the first parameter, so make sure to handle this correctly in your app.
  • submit - when the default "submit" button is clicked - if you override the default completeButton slot, this event won't be called (example in Example.vue)
    function onSubmit(questionList) {
      // Handle submit event.
    }
  • answer - gets fired after a question is answered
    function onAnswer(questionAnswered) {
      // Handle answer event.
    }
  • step - gets fired when a new step is displayed
    function onStep(activeQuestionId, activeQuestion) {
      // Handle step event.
    }

FlowForm component slots

  • complete - Complete/submit screen content
    • This is the content of your custom complete screen, by default the thankYouText language string is used, but you can customize this screen to look like you want
  • completeButton - Complete/submit screen button
    • If you override the button, the complete event will not be called so you'll need to handle the button onClick event manually

Submitting data

  • the submit event emits an event with the question list as the only parameter. You can then send the data to your backend using fetch API or something like Axios. If you've overridden the default completeButton slot, implement the complete event to know when the user is on the complete screen and handle the rest manually.
  • when your form contains one or more QuestionType.File question types, make sure you're using the FormData interface to correctly send all of the gathered data to your back-end, eg.:
    function onSubmit(questionList) {
      // Handle submit event.
      const formData = new FormData()
    
      questionList.forEach(question => {
        formData.append(question.id, question.answer)
      })
    
      fetch(url, {
        method: 'POST',
        body: data
      })
    }

Theming

Using a pre-built theme

  • Vue Flow Form comes with several out-of-the box theme CSS files. Theme files include all common color and typography styles.
  • When using npm or CDN, just import one of the available themes together with the base CSS file
  • CSS variables support for legacy browsers is included in the example project. If you need to support legacy browsers in your project when using the npm package, either create an alternate theme without using variables or use css-vars-ponyfill
  • There are three pre-built themes:
  • To use a theme when using the npm package, import it in your style block:
    @import  '~@ditdot-dev/vue-flow-form/dist/vue-flow-form.theme-[THEME NAME].css';
  • When using the CDN version, reference the CSS using one of the CDN links above
  • Dark mode support is enabled by using the prefers-color-scheme media query
    @media (prefers-color-scheme: dark) {
      /* dark mode styles go here */
    }

Defining a custom theme

  • Customize existing themes as you like or create your own. The easiest way to create a new theme is to copy and change one of the pre-built theme CSS files from the src/assets/css/themes folder
  • When using npm or CDN, customize/create the theme and import it into your app as you would do with the pre-built theme
  • You can further customize other aspects of the app for your particular needs in the src/assets/css/common.css

Layout options

  • Standalone (default) layout is suitable for a full-page display, or you can use a non-standalone layout - more suitable for integrating and embedding into your existing layout.
  • To use Vue Flow Form as an integrated component embed it into an applicable HTML element and pass false to the standalone prop on the FlowForm component instance:
    <flow-form v-bind:standalone="false"> <!-- ... --> </flow-form>

Multilanguage Support

  • To translate the form fields and values into your preferred language, create a language object and define language options
  • Use the language object with the LanguageModel instance
    // npm example
    import { FlowForm, QuestionModel, QuestionType, ChoiceOption, LanguageModel, MatrixRow, MatrixColumn } from '@ditdot-dev/vue-flow-form';
    
    export default {
      name: 'example',
      components: {
        FlowForm
      },
      data() {
        return {
          language: new LanguageModel({
            continue: 'Fortsetzen',
            pressEnter: 'Drücken Sie ENTER',
            otherPrompt: 'Andere',
            submitText: 'Einreichen'
            // ...
          })
          // ...
        }
      }
    }
    // npm example
    import FlowForm, { QuestionModel, QuestionType, ChoiceOption, LanguageModel } from '@ditdot-dev/vue-flow-form@1.1.7';
    
    export default {
      name: 'example',
      components: {
        FlowForm
      },
      data() {
        return {
          language: new LanguageModel({
            continue: 'Fortsetzen',
            pressEnter: 'Drücken Sie ENTER',
            otherPrompt: 'Andere',
            submitText: 'Einreichen'
            // ...
          })
          // ...
        }
      }
    }

Source code and demo examples

  • Questionnaire (default):
    • example containing a sample questionnaire
    • Live demo
  • Quiz:
    • example showing how the component can be used in a more advanced way
    • this example shows the number of correctly answered questions after submitting the form, along with an accompanying message
    • to view this quiz example, change the entry point in vue.config.js to 'examples/quiz/main.js'
    • Live demo
  • Support page:
    • example of a support ticket form
    • this example allows you to submit a support request or to check your existing ticket status
    • to view this customer support example, change the entry point in vue.config.js to 'examples/support-page/main.js'
    • Live demo

Files/folders

  • CSS: src/assets/css
  • Vue components: src/components, src/components/QuestionTypes
  • Models: src/models

Demo project usage

Set corresponding JavaScript entry file in vue.config.js (examples in examples /example-name / Example.vue)

module.exports = {
  publicPath: '',
  pages: {
    index: {
      entry: 'examples/questionnaire/main.js', // Replace with your .js entry file path
      template: 'public/index.html',
      filename: 'index.html'
    }
  }
}

How to contribute:

Pull requests and potential features are welcome.

# clone repo
$ git clone https://github.com/ditdot-dev/vue-flow-form.git

# create a new branch
$ git checkout -b new_branch_name

# make changes, test and submit pull request with description of changes

If you think you found a bug, perform the Issues search to see if the problem has already been reported. If you're unable to find an issue addressing it, create a new issue that thoroughly explains the problem, with clear steps to reproduce.

Made with Vue.js

Last updated: Jun 16, 2023