# Group
The group classification
only contains the input type group. It is a special input used to
logically group one or more fields together. It is useful for:
# Data organization
You can use the group type to logically group data. The fields nested under a
group will be bundled together as their own object.
<FormulateForm
  v-model="fields"
>
  <FormulateInput
    type="text"
    name="name"
    label="Your name"
  />
  <FormulateInput
    type="group"
    name="address"
  >
    <FormulateInput
      type="text"
      name="address"
      label="Street address"
    />
    <FormulateInput
      type="text"
      name="city"
      label="City"
    />
    <FormulateInput
      type="select"
      name="state"
      label="State"
      :options="{VA: 'Virginia', CA: 'California', NY: 'New York'}"
    />
  </FormulateInput>
</FormulateForm>
{}Note
For consistency, the value of a group will always be an array even if
the field is not repeatable. If you need a plain object, we recommend
destructuring the array inside a form submit handler.
# Repeatable groups
By setting the repeatable prop to true anything inside our group becomes
infinitely repeatable including non-formulate elements. An "add more" button is
also added, along with a remove button for each item.  A repeatable group can
be further customized with special props and slots.
View source code
<template>
  <div class="form-wrapper">
    <FormulateForm
      v-model="formData"
    >
      <FormulateInput
        type="group"
        name="attendees"
        :repeatable="true"
        label="Who is going to attend?"
        add-label="+ Add Attendee"
        validation="required"
      >
        <div class="attendee">
          <FormulateInput
            name="name"
            validation="required"
            label="Attendee’s name"
          />
          <FormulateInput
            type="email"
            name="email"
            validation="required|email"
            label="Attendee’s email"
          />
          <strong class="price" v-text="`$100`" />
        </div>
      </FormulateInput>
      <FormulateInput
        type="radio"
        label="Select your payment method"
        name="payment"
        :options="{paypal: 'PayPal', credit: 'Credit Card'}"
      />
      <strong>Total: {{ total }}</strong>
      <FormulateInput
        type="submit"
        label="Purchase tickets"
      />
    </FormulateForm>
    <code class="code code--block">{{ formData }}</code>
  </div>
</template>
<script>
export default {
  data () {
    return {
      formData: {}
    }
  },
  computed: {
    total () {
      const count = Array.isArray(this.formData.attendees) ? this.formData.attendees.length : 1
      return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD'}).format(count * 100)
    }
  }
}
</script>
<style scoped>
.form-wrapper {
  padding: 2em;
  border: 1px solid #a8a8a8;
  border-radius: .5em;
  box-sizing: border-box;
}
@media (min-width: 650px) {
  .attendee {
    display: flex;
  }
}
@media (min-width: 720px) {
  .attendee {
    display: block;
  }
}
@media (min-width: 850px) {
  .attendee {
    display: flex;
  }
  .attendee .formulate-input {
    margin-right: 1.5em;
  }
}
.attendee .formulate-input {
  margin-right: 2em;
  margin-bottom: 0;
}
strong {
  display: block;
  margin: 1em 0;
}
strong.price {
  margin-top: 1.25em;
  margin-bottom: 0;
  height: 2.5em;
  display: inline-flex;
  align-items: center;
}
code {
  margin-top: 2em;
}
</style>
{}Warning
It's easy to use groups to create very large forms with deep nesting, however
bear in mind that all the inputs have dependencies on one another — doing so
can create performance issues. If you notice performance issues, try leveraging
the debounce prop on the form or inputs.
# Validation
By default, fields inside a group validate just like any other fields. Making
a field inside a group required, for example, would prevent that form from
submitting until that field has been completed. However, you can also place
validation rules directly on the group. So placing a "required" rule on the
group component ensures at least 1 repeatable item is in your group.
<FormulateForm>
  <FormulateInput
    type="group"
    label="Add your social media pages"
    :repeatable="true"
    validation-name="social media links"
    validation="min:2,length"
    add-label="+ Social link"
  >
    <FormulateInput
      label="Social media link"
      validation="required|url"
    />
  </FormulateInput>
  <FormulateInput
    type="submit"
  />
</FormulateForm>
Note
There is no blur event for a group type, so by default validation errors will
be shown when someone attempts to submit a form. If you prefer errors to be
immediately show, consider using error-behavior="live".
Note
The confirm-rule currently does not work within groups. This will be fixed in an upcoming release. See tracking issue
# Applying custom validation rules
Applying custom validation rules to a group field allows for very granular and
powerful rules to meet your specific scenario. These rules give you
access to the data in all of its sub-fields allowing complex cross-field
validation.
View source code
<template>
  <FormulateForm
    class="form-wrapper"
    @submit="handle"
  >
    <FormulateInput
      name="name"
      label="Your name"
      placeholder="Your name"
      validation="required"
    />
    <FormulateInput
      label="Your shipping address"
      type="group"
      validation="address"
      :validation-rules="{ address: addressRule }"
      :validation-messages="{ address: addressMessage }"
    >
      <FormulateInput
        name="street"
        placeholder="Street address"
      />
      <div class="triple">
        <FormulateInput
          name="city"
          placeholder="City"
        />
        <FormulateInput
          type="select"
          name="state"
          :options="{VA: 'VA', PA: 'PA', WA: 'WA'}"
          placeholder="State"
        />
        <FormulateInput
          name="zip"
          placeholder="Zip"
        />
      </div>
    </FormulateInput>
    <FormulateInput
      type="submit"
    />
  </FormulateForm>
</template>
<script>
export default {
  methods: {
    addressRule ({ value }) {
      if (Array.isArray(value)) {
        const [address] = value
        return address.street && address.city && address.state && address.zip
      }
      return false
    },
    addressMessage ({ value }) {
      if (Array.isArray(value)) {
        const [address] = value
        const missing = ['street', 'city', 'state', 'zip'].reduce((missing, field) => {
          if (!address[field]) {
            missing.push(field)
          }
          return missing
        }, [])
        return `Your shipping address still requires: ${missing.join(', ')}.`
      }
      return 'Please fill out your shipping address.'
    },
    handle () {
      alert('All validation complete, form submitted.')
    }
  }
}
</script>
<style scoped>
.form-wrapper {
  padding: 2em;
  border: 1px solid #a8a8a8;
  border-radius: .5em;
  box-sizing: border-box;
  max-width: 450px;
}
.form-wrapper::v-deep .formulate-input-element {
  max-width: none;
}
@media (min-width: 650px) {
  .triple {
    display: flex;
  }
  .triple .formulate-input {
    margin-bottom: .25em;
    margin-right: 1em;
    flex-grow: 1;
  }
  .triple .formulate-input[data-classification="select"] {
    flex: 0 0 5em;
  }
  .triple .formulate-input:last-child {
    margin-right: 0;
  }
}
@media (min-width: 720px) {
  .triple {
    display: block;
  }
  .triple .formulate-input {
    margin-bottom: 1.5em;
    margin-right: 0;
  }
}
@media (min-width: 850px) {
  .triple {
    display: flex;
  }
  .triple .formulate-input {
    margin-bottom: .25em;
    margin-right: 1em;
  }
  .triple .formulate-input:last-child {
    margin-right: 0;
  }
}
</style>
# Settings errors on groups 2.5
When setting explicit errors on group input we need a way to indicate which
index the errant field is at. To make this as simple as possible, use the
group-errors prop along with "dot notation" to reference inputs in their
index. For example:
<FormulateInput
  type="group"
  :repeatable="true"
  name="invitees"
  :group-errors="{
    '0.email': 'This email is already in use',
    '1.name': 'Pretty sure Rensmold isn’t a real last name'
  }"
  :value="[
    { name: 'Todd Berkins', email: 'todd@example.com' },
    { name: 'Stella Rensmold', email: 'stella@example.com' },
  ]"
>
  <FormulateInput
    name="name"
    label="Invitee's name"
  />
  <FormulateInput
    name="email"
    label="What is this user's email?"
  />
</FormulateInput>
Notice how the errors always begin with the index of the group. The proeprties
of the group-errors prop must always begin with the index of the group they
are being applied to.
You can also apply group errors using dot notation from a <FormulateForm>.
# Index of current group
To manipulate a distinct group field, it is helpful to get the index of the current group item. Luckily, slots can help. The default slot for instance offers the index as a context variable of groupProps:
Example:
 <FormulateInput
    type="group"
    name="attendees"
    :repeatable="true"
    add-label="+ Add Attendee"
    #default="{ index }"
>
  <p>This is Group # {{ index }} </p>
  <FormulateInput
    name="price"
    disabled
    :value="getPrice(index)"
    label="Price"
  />
</FormulateInput>
# Props
The group field has a few unique props:
| Prop | Description | 
|---|---|
| add-label | When repeatable, this is the label to display on the "+ Add" button (defaults to label || name). | 
| limit | When repeatable, this is the maximum number of group items. | 
| minimum | When repeatable, this is the minimum number of group items. | 
| remove-label | When repeatable, this is the label to display on the "Remove" button. | 
| remove-position | Show the remove button beforeorafterthe group inputs (defaults tobefore) | 
| repeatable | Booleanindicates if the field is repeatable. | 
| group-errors | Objectof dot notation properties (like0.name) with errors. | 
# Slots
The group input has several unique slots (and matching Slot Components):
| Slot name | Description | 
|---|---|
| addMore | The add more button when repeatable.The context object in this slot includes an addMorefunction that should be called to add new items. | 
| default | Anything in the default slot will be considered part of the group, and become repeatableif applicable. The context object will additionally have an "index" property. | 
| grouping | The primary repeatable area, responsible for rendering the inner content. | 
| remove | The remove button when repeatable.The context object in this slot includes the indexand aremoveItemfunction that should be called to remove that item. | 
| repeatable | Responsible for rendering each row of inputs. The context object in this slot includes a removeItemfunction that should be called to remove that item. | 
# Events 2.5
The group input type has two unique events:
| Event name | Description | 
|---|---|
| @repeatableAdded | Emitted when a new repeatable item is added to the group. | 
| @repeatableRemoved | Emitted when a repeatable item is removed from the group. | 
# Custom class keys
In addition to all global class keys following are available:
| Key | Default | Description | 
|---|---|---|
| grouping | .formulate-input-grouping | A wrapper around all repeatable fields (only exists when repeatable) | 
| groupRepeatable | .formulate-input-group-repeatable | A wrapper around each set of grouped fields (exists even for non-repeatable groups). | 
| groupRepeatableRemove | .formulate-input-group-repeatable-remove | The remove button for a field group. | 
| groupAddMore | .formulate-input-group-add-more | The wrapper around the add more button for repeatable groups. | 
