) => ReactNode)`
Children nodes of CartForm. Children can be a render prop that receives the fetcher.
### route
value: `string`
The route to submit the form to. Defaults to the current route.
### fetcherKey
value: `string`
Optional key to use for the fetcher.
## Examples
Creates a form for managing cart operations. Use `CartActionInput` to accept form inputs of known type.
### CartForm using HTML input tags as form inputs
```jsx
import {json} from '@remix-run/server-runtime';
import {CartForm} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
export default function Note() {
return (
);
}
export async function action({request, context}) {
const cart = context.cart;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let status = 200;
let result;
if (action === CartForm.ACTIONS.NoteUpdate) {
result = await cart.updateNote(inputs.note);
} else {
invariant(false, `${action} cart action is not defined`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {status, headers});
}
```
```tsx
import {type ActionFunctionArgs, json} from '@remix-run/server-runtime';
import {
type CartQueryDataReturn,
type HydrogenCart,
CartForm,
} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
export default function Note() {
return (
);
}
export async function action({request, context}: ActionFunctionArgs) {
const cart = context.cart as HydrogenCart;
// cart is type HydrogenCart or HydrogenCartCustom
// Declare cart type in remix.env.d.ts for interface AppLoadContext to avoid type casting
// const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let status = 200;
let result: CartQueryDataReturn;
if (action === CartForm.ACTIONS.NoteUpdate) {
result = await cart.updateNote(inputs.note);
} else {
invariant(false, `${action} cart action is not defined`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {status, headers});
}
```
### Custom actions
```jsx
import {json} from '@remix-run/server-runtime';
import {CartForm} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
export default function Cart() {
return (
);
}
export async function action({request, context}) {
const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let status = 200;
let result;
if (action === 'CustomEditInPlace') {
result = await cart.addLines(inputs.addLines);
result = await cart.removeLines(inputs.removeLines);
} else {
invariant(false, `${action} cart action is not defined`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {status, headers});
}
```
```tsx
import {type ActionFunctionArgs, json} from '@remix-run/server-runtime';
import {
type CartQueryDataReturn,
type HydrogenCart,
CartForm,
} from '@shopify/hydrogen';
import {type CartLineInput} from '@shopify/hydrogen-react/storefront-api-types';
import invariant from 'tiny-invariant';
export default function Cart() {
return (
);
}
export async function action({request, context}: ActionFunctionArgs) {
const cart = context.cart as HydrogenCart;
// cart is type HydrogenCart or HydrogenCartCustom
// Declare cart type in remix.env.d.ts for interface AppLoadContext to avoid type casting
// const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let status = 200;
let result: CartQueryDataReturn;
if (action === 'CustomEditInPlace') {
result = await cart.addLines(inputs.addLines as CartLineInput[]);
result = await cart.removeLines(inputs.removeLines as string[]);
} else {
invariant(false, `${action} cart action is not defined`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {status, headers});
}
```
### CartForm with fetcher
```jsx
import {useFetcher} from '@remix-run/react';
import {json} from '@remix-run/server-runtime';
import {CartForm} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
export function ThisIsGift({metafield}) {
const fetcher = useFetcher();
const buildFormInput = (event) => ({
action: CartForm.ACTIONS.MetafieldsSet,
inputs: {
metafields: [
{
key: 'custom.gift',
type: 'boolean',
value: event.target.checked.toString(),
},
],
},
});
return (
{
fetcher.submit(
{
[CartForm.INPUT_NAME]: JSON.stringify(buildFormInput(event)),
},
{method: 'POST', action: '/cart'},
);
}}
/>
);
}
export async function action({request, context}) {
const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let status = 200;
let result;
if (action === CartForm.ACTIONS.MetafieldsSet) {
result = await cart.setMetafields(inputs.metafields);
} else {
invariant(false, `${action} cart action is not defined`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {status, headers});
}
```
```tsx
import {useFetcher} from '@remix-run/react';
import {type ActionFunctionArgs, json} from '@remix-run/server-runtime';
import {
type CartQueryDataReturn,
type HydrogenCart,
CartForm,
type CartActionInput,
} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
import type {Cart} from '@shopify/hydrogen/storefront-api-types';
export function ThisIsGift({metafield}: {metafield: Cart['metafield']}) {
const fetcher = useFetcher();
const buildFormInput: (
event: React.ChangeEvent,
) => CartActionInput = (event) => ({
action: CartForm.ACTIONS.MetafieldsSet,
inputs: {
metafields: [
{
key: 'custom.gift',
type: 'boolean',
value: event.target.checked.toString(),
},
],
},
});
return (
{
fetcher.submit(
{
[CartForm.INPUT_NAME]: JSON.stringify(buildFormInput(event)),
},
{method: 'POST', action: '/cart'},
);
}}
/>
);
}
export async function action({request, context}: ActionFunctionArgs) {
const cart = context.cart as HydrogenCart;
// cart is type HydrogenCart or HydrogenCartCustom
// Declare cart type in remix.env.d.ts for interface AppLoadContext to avoid type casting
// const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let status = 200;
let result: CartQueryDataReturn;
if (action === CartForm.ACTIONS.MetafieldsSet) {
result = await cart.setMetafields(inputs.metafields);
} else {
invariant(false, `${action} cart action is not defined`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {status, headers});
}
```