--- url: https://docs.youcan.shop/themes/tags/form.md --- # `form` Outputs an HTML `
` with the inputs the storefront needs to handle it. The form works without JavaScript: the storefront handles the post and redirects back, or to `return_to`. ```liquid {% form 'type', object, attribute: value %} content {% endform %} ``` * `type`: the form type, one of the types below. The quotes are optional. * `object`: the object some types need, for example a product. * `attribute: value`: any HTML attribute of the `` tag, for example `id`, `class` or `data-role`. Values are escaped. * `return_to`: where to go after a successful post. See [Return to](#return-to). Every posted form also outputs a CSRF token, a `form_type` input and a hidden spam field. Do not remove them. ```liquid {% form 'contact', id: 'contact-form', class: 'contact' %} {% endform %} ``` ```html
…
``` ## The `form` object Inside a form, `form` describes the last post of that form type. It is empty on a normal page view. | Name | Type | Description | | --------------------- | ------------------------------------------ | ----------------------------------------------------------------- | | `type` | [string](../basics/types#string) | The form type | | `posted_successfully` | [boolean](../basics/types#boolean) | Whether this form was posted and the post succeeded | | `errors` | form errors | The errors of the post, or nil | | `values` | object | The submitted values when the post failed, without passwords | | any field name | [string](../basics/types#string) | The same submitted values, for example `form.email` | `form.errors` has: * `messages`: the first message of each field, for example `form.errors.messages.email`. * `translated_fields`: a readable name for each field, for example `Email` for `email`. * Looping over `form.errors` gives pairs: `error[0]` is the field, `error[1]` its messages. The `default_errors` filter outputs all messages as a list: ```liquid {% form 'contact' %} {% if form.posted_successfully %}

{{ 'contact.success' | t }}

{% endif %} {{ form.errors | default_errors }} {% endform %} ``` ```html
``` ## Return to `return_to` sets where to go after a successful post. A failed post always goes back to the page of the form, so the errors can show. * A path on the store, for example `/cart`. * `back`: the page the form was on. * `checkout`: the checkout, one page or step by step, depending on the cart. Other values, including URLs on other domains, are ignored. ```liquid {% form 'product', product, return_to: 'checkout' %} {% endform %} ``` ## Types ### `product` Adds a product to the cart. With a product as `object`, the form outputs the `id` input of the selected or first available variant. A product with "skip to checkout" goes to the checkout after the post, unless you set `return_to`. | Input | Required | Description | | ---------------- | -------- | ------------------------------------------------------ | | `id` | yes | The variant id. Output for you when you pass a product | | `quantity` | yes | The quantity | | `attachedImage` | no | The URL of an image the customer uploaded, for variants that need one | ```liquid {% form 'product', product %} {% endform %} ``` A `select` named `id` inside the form replaces the variant the form outputs. ### `express_checkout` Places an order from the product page in one step. Pass the product as `object`. After the post the customer goes to the thank you page, to the upsell offers, or to the shipping or payment step when the store needs them. `return_to` is not used. | Input | Required | Description | | -------------------------------------------- | -------------------- | ------------------------------ | | `quantity` | yes | The quantity | | checkout fields, for example `first_name` and `phone` | as set by the store | The customer details | Field errors come back in `form.errors`. ### `cart` Updates the cart. | Input | Required | Description | | ------------------ | -------- | ------------------------------------------------------------ | | `updates[ITEM_ID]` | no | The new quantity of a cart item. `0` removes it | | `note` | no | The cart note. Read it with [`cart.note`](../objects/cart) | | `clear` | no | Removes all items when present | | `checkout` | no | Goes to the checkout after the update when present | ```liquid {% form 'cart', cart %} {% for item in cart.items %} {% endfor %} {% endform %} ``` ### `coupon` Applies a coupon to the cart. | Input | Required | Description | | -------- | -------- | --------------- | | `coupon` | yes | The coupon code | ### `coupon_remove` Removes the coupon from the cart. It needs no inputs. ### `product_review` Adds a review to a product. Pass the product as `object`. Reviews wait for the seller's approval. | Input | Required | Description | | ------------ | -------- | --------------------------------- | | `ratings` | yes | A rating from 0 to 5 | | `content` | no | The review text, 5 to 2000 characters | | `first_name` | no | The reviewer's first name | | `last_name` | no | The reviewer's last name | | `email` | no | The reviewer's email | | `images[]` | no | Image URLs | ### `contact` Sends a message to the seller. The form outputs a captcha. | Input | Required | Description | | --------- | -------- | ---------------------- | | `email` | yes | The customer's email | | `subject` | yes | The subject | | `message` | yes | The message | ## Customer types These types handle customer accounts. Use them in the [customer templates](/themes/templates/overview#template-types). The `customer_login`, `create_customer`, `recover_customer_password`, `reset_customer_password` and `customer` forms output a captcha, and the post fails without it. ### `customer_login` Logs the customer in. After the post the customer goes to `return_to`, or to the home page. | Input | Required | Description | | ---------- | -------- | ------------------------------------------- | | `email` | yes | The customer's email | | `password` | yes | The password | | `remember` | no | Keeps the customer logged in when checked | ```liquid {% form 'customer_login', return_to: routes.account_url %} {{ form.errors | default_errors }} {% endform %} ``` ### `create_customer` Creates an account. After the post the customer goes to the login page. When the email belongs to a past customer without an account, the store sends an email to set the password. | Input | Required | Description | | ----------------------- | -------- | ----------------------------------- | | `email` | yes | The customer's email | | `password` | yes | The password, 6 to 72 characters | | `password_confirmation` | yes | The same password | | `first_name` | no | The first name | | `last_name` | no | The last name | | `phone` | no | The phone number | ### `recover_customer_password` Sends a password reset email. The store sends it only when an account exists for the email, and the post succeeds in both cases. | Input | Required | Description | | ------- | -------- | -------------------- | | `email` | yes | The customer's email | ### `reset_customer_password` Sets a new password from the link in the reset email. Use it in the [`customer-reset-password`](/themes/templates/template-types/customer-reset-password) template. The form takes the reset link from the page URL. After the post the customer is logged in and goes to the home page. | Input | Required | Description | | ----------------------- | -------- | ----------------------------------- | | `password` | yes | The new password, 6 to 72 characters | | `password_confirmation` | yes | The same password | ### `customer_update` Updates the logged in customer. | Input | Required | Description | | ----------------------- | ----------------------------------------- | ----------------------------------- | | `first_name` | yes | The first name, 2 or more characters | | `last_name` | yes | The last name, 2 or more characters | | `email` | yes | The email | | `phone` | no | The phone number | | `password` | no | A new password, 6 to 72 characters | | `password_confirmation` | with `password` | The same password | | `current_password` | when the email or the password changes | The current password | ```liquid {% form 'customer_update' %} {{ form.errors | default_errors }} {% endform %} ``` ### `customer` Subscribes an email to the store's marketing emails. The customer does not need an account. | Input | Required | Description | | ------- | -------- | ----------- | | `email` | yes | The email | ### `customer_address` Adds or updates an address of the logged in customer. Pass `customer.new_address` as `object` to add an address. Pass an address from `customer.addresses` to update it: the form outputs its `id` input. A customer can save up to 50 addresses. | Input | Required | Description | | -------------- | -------- | ------------------------------------------------ | | `first_line` | yes | The first address line | | `city` | yes | The city | | `country_code` | yes | The country code, for example `MA` | | `first_name` | no | The first name | | `last_name` | no | The last name | | `company` | no | The company | | `second_line` | no | The second address line | | `region` | no | The region | | `zip_code` | no | The zip code | | `phone` | no | The phone number | | `default` | no | `1` makes it the default address | ```liquid {% for address in customer.addresses %} {% form 'customer_address', address %} {% endform %} {% endfor %} {% form 'customer_address', customer.new_address %} {% endform %} ``` ### `customer_address_remove` Removes an address. Pass the address as `object`. It needs no inputs. ```liquid {% form 'customer_address_remove', address %} {% endform %} ```