> ## Documentation Index
> Fetch the complete documentation index at: https://docs.supercycle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Methods

> Add every method a product offers to the product page and let Supercycle control the add to cart button

export const CalendarRentalPdp = () => {
  const PERIODS = [{
    days: 4,
    price: 63.99
  }, {
    days: 7,
    price: 83.99
  }, {
    days: 14,
    price: 117.99
  }, {
    days: 30,
    price: 161.99
  }];
  const ADDONS = [{
    id: "damage",
    title: "Damage protection",
    desc: "Covers accidental damage during your rental",
    price: 9
  }, {
    id: "cleaning",
    title: "Cleaning",
    desc: "",
    price: 12,
    required: true
  }];
  const START = new Date(2025, 0, 10);
  const [period, setPeriod] = useState(0);
  const [addons, setAddons] = useState({
    damage: false,
    cleaning: true
  });
  const money = n => "$" + n.toFixed(2);
  const fmt = d => d.getDate() + " " + d.toLocaleString("en", {
    month: "short"
  }) + " " + String(d.getFullYear()).slice(2);
  const endDate = new Date(START);
  endDate.setDate(START.getDate() + PERIODS[period].days);
  const perDay = PERIODS[period].price / PERIODS[period].days;
  const addonTotal = ADDONS.reduce((s, a) => s + (addons[a.id] ? a.price : 0), 0);
  const total = PERIODS[period].price + addonTotal;
  const toggleAddon = a => {
    if (a.required) return;
    setAddons({
      ...addons,
      [a.id]: !addons[a.id]
    });
  };
  const t = {
    border: "#cccccc",
    text: "#000000",
    subdued: "#656565",
    accent: "#000000",
    radius: 8
  };
  const chip = selected => ({
    border: "1px solid " + (selected ? t.accent : t.border),
    background: selected ? t.accent : "#ffffff",
    color: selected ? "#ffffff" : t.text,
    borderRadius: t.radius,
    padding: 6,
    minHeight: 28,
    display: "flex",
    alignItems: "center",
    lineHeight: 1,
    fontSize: 11,
    cursor: "pointer",
    transition: "background-color 150ms ease, border-color 150ms ease, color 150ms ease"
  });
  const label = {
    display: "block",
    fontSize: 11,
    color: t.subdued,
    marginBottom: 3
  };
  const line = {
    display: "flex",
    justifyContent: "space-between",
    fontSize: 11
  };
  const windowRef = useRef(null);
  const [zoom, setZoom] = useState(0.4);
  useEffect(() => {
    const el = windowRef.current;
    if (!el || typeof ResizeObserver === "undefined") return undefined;
    const fit = () => setZoom(Math.max(0.2, Math.min(1, el.clientWidth / 853)));
    fit();
    const ro = new ResizeObserver(fit);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);
  return <div className="not-prose sc-cpdp" aria-label="Example calendar rental product page">
      <style>{`
        .sc-cpdp { width: 100%; min-width: 0; font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 11px; color: #000; }
        .sc-cpdp button { font: inherit; margin: 0; appearance: none; text-align: left; }
        .sc-cpdp button:focus-visible { outline: 2px solid #000; outline-offset: 2px; }
        .sc-cpdp-window { width: 100%; min-width: 0; max-width: 640px; height: auto; max-height: 520px; margin: 0 auto; display: flex; flex-direction: column; touch-action: pan-y;
          background: linear-gradient(135deg, #ffffff 45%, #f7f6f2 100%); border-radius: 10px; overflow: hidden;
          box-shadow: 0 0 0 1px rgba(11,13,24,.06), 0 1px 2px rgba(11,13,24,.024), 0 3px 6px rgba(11,13,24,.03), 0 8px 14px rgba(11,13,24,.035), 0 16px 28px rgba(11,13,24,.04); }
        .sc-cpdp-titlebar { position: relative; flex: none; display: flex; align-items: center; gap: 6px; padding: 9px 12px; border-bottom: 1px solid #ebebeb; }
        .sc-cpdp-dot { width: 9px; height: 9px; border-radius: 50%; background: #e3e3e3; }
        .sc-cpdp-url { margin: 0 auto; font-size: 11px; color: #85817a; background: #f3f2ee; border-radius: 6px; padding: 3px 10px; line-height: 1.2; pointer-events: none; }
        /* The page: everything below the title bar. Desktop keeps an inner
           scrollbar; touch devices pass the swipe to the docs page. */
        .sc-cpdp-page { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; background: #fff; scrollbar-width: thin; scrollbar-color: #d6d3cc transparent; }
        .sc-cpdp-page::-webkit-scrollbar { width: 6px; }
        .sc-cpdp-page::-webkit-scrollbar-thumb { background: #d6d3cc; border-radius: 3px; }
        @media (pointer: coarse) { .sc-cpdp-page { overflow: hidden; overscroll-behavior: auto; } }
        .sc-cpdp-store { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 12px 16px; font-size: 11px; }
        .sc-cpdp-store-name { font-family: "Instrument Serif", Georgia, "Times New Roman", serif; font-size: 15px; letter-spacing: -0.01em; color: #202603; }
        .sc-cpdp-store-nav { display: flex; gap: 12px; color: #333; }
        .sc-cpdp-store-icons { display: flex; justify-content: flex-end; align-items: center; gap: 12px; color: #333; }
        .sc-cpdp-store-icons svg { width: 14px; height: 14px; }
        .sc-cpdp-avatar { width: 16px; height: 16px; border-radius: 50%; background: #2f6bff; color: #fff; font-size: 8px; font-weight: 600; display: grid; place-items: center; }
        .sc-cpdp-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; padding: 4px 16px 16px; }
        .sc-cpdp-media { position: sticky; top: 0; }
        .sc-cpdp-product { display: block; }
        .sc-cpdp-placeholder { aspect-ratio: 4 / 5; border-radius: 4px; background: #f3f2ee; color: #c9c5bc; display: grid; place-items: center; }
        .sc-cpdp-placeholder svg { width: 40px; height: 40px; }
        .sc-cpdp-panel { display: flex; flex-direction: column; gap: 12px; padding: 0; }
        .sc-cpdp-desc { padding: 16px; display: grid; gap: 12px; font-size: 11px; line-height: 1.5; color: #333; border-top: 1px solid #ebebeb; }
        .sc-cpdp-desc h4 { margin: 0 0 4px; font-size: 11px; font-weight: 600; color: #000; }
        .sc-cpdp-desc p { margin: 0; }
        .sc-cpdp-desc ul { margin: 0; padding-left: 16px; list-style: disc; }
        .sc-cpdp .sc-cpdp-cta { background: #1a1a1a; color: #fff; border: 0; border-radius: 8px; text-align: center; font-size: 12px; font-weight: 550; padding: 10px 0; width: 100%; cursor: pointer; }
        .sc-cpdp .sc-cpdp-cta:hover { background: #303030; }
      `}</style>

      <div className="sc-cpdp-window" ref={windowRef}>
        <div className="sc-cpdp-titlebar">
          <span className="sc-cpdp-dot" />
          <span className="sc-cpdp-dot" />
          <span className="sc-cpdp-dot" />
          <span className="sc-cpdp-url">yourstore.com/products/all-mountain-ski-set</span>
        </div>

        <div className="sc-cpdp-page">
        <div className="sc-cpdp-zoom" style={{
    zoom,
    width: 853
  }}>
          <div className="sc-cpdp-store" aria-hidden="true">
            <span className="sc-cpdp-store-nav">
              <span>Methods</span>
              <span>Collections</span>
              <span>Plans</span>
            </span>
            <span className="sc-cpdp-store-name">Summit store</span>
            <span className="sc-cpdp-store-icons">
              <svg viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.4" /><path d="M10.5 10.5L14 14" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /></svg>
              <span className="sc-cpdp-avatar">M</span>
              <svg viewBox="0 0 16 16" fill="none"><path d="M3 5.5h10l-.8 8H3.8L3 5.5z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" /><path d="M5.5 5.5V4.5a2.5 2.5 0 015 0v1" stroke="currentColor" strokeWidth="1.4" /></svg>
            </span>
          </div>
        <div className="sc-cpdp-body">
          {}
          <div className="sc-cpdp-media" aria-hidden="true">
            <div className="sc-cpdp-placeholder">
              <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
                <rect x="6" y="10" width="36" height="28" rx="3" stroke="currentColor" strokeWidth="2" />
                <circle cx="17" cy="20" r="3.5" stroke="currentColor" strokeWidth="2" />
                <path d="M8 34l10-9 7 6 6-5 9 8" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </div>
          </div>

          {}
          <div className="sc-cpdp-panel">
            <div className="sc-cpdp-product">
              <div style={{
    fontSize: 16,
    fontWeight: 550,
    lineHeight: 1.2
  }}>All-mountain ski set</div>
              <div style={{
    fontSize: 12,
    color: t.subdued,
    marginTop: 4
  }}>From $5.40 per day</div>
            </div>


            <div>
              <div style={{
    border: "1px solid " + t.accent,
    outline: "1px solid " + t.accent,
    borderRadius: t.radius,
    padding: 12,
    background: "#ffffff"
  }}>
                <div style={{
    display: "flex",
    alignItems: "flex-start",
    gap: 6,
    lineHeight: 1
  }}>
                  <span style={{
    position: "relative",
    width: 14,
    height: 14,
    flexShrink: 0,
    borderRadius: "50%",
    boxShadow: "inset 0 0 0 1px " + t.accent
  }}>
                    <span style={{
    position: "absolute",
    inset: 3,
    borderRadius: "50%",
    background: t.accent
  }} />
                  </span>
                  <span style={{
    flex: 1,
    minWidth: 0,
    display: "flex",
    flexDirection: "column",
    gap: 4
  }}>
                    <span style={{
    display: "flex",
    justifyContent: "space-between",
    gap: 6
  }}>
                      <span style={{
    fontSize: 12
  }}>Rent</span>
                      <span style={{
    fontSize: 12,
    marginLeft: "auto"
  }}>From $5.40 per day</span>
                    </span>
                    <span style={{
    fontSize: 10,
    color: t.subdued,
    textAlign: "right"
  }}>Yours for 4 to 30 days</span>
                  </span>
                </div>

                <div style={{
    marginTop: 12,
    borderTop: "1px solid " + t.border,
    paddingTop: 12,
    display: "grid",
    gap: 12
  }}>
                  {}
                  <div>
                    <span style={label}>Rental period</span>
                    <div style={{
    display: "grid",
    gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
    gap: 6
  }}>
                      {PERIODS.map((p, i) => {
    const on = i === period;
    return <button key={p.days} type="button" aria-pressed={on} onClick={() => setPeriod(i)} style={{
      ...chip(on),
      flexDirection: "column",
      alignItems: "center",
      justifyContent: "center",
      gap: 4,
      minHeight: 34,
      textAlign: "center"
    }}>
                            <span style={{
      fontSize: 11
    }}>{p.days} days</span>
                            <span style={{
      fontSize: 10,
      color: on ? "#ffffff" : t.subdued
    }}>{money(p.price)}</span>
                          </button>;
  })}
                    </div>
                  </div>

                  {}
                  <div style={{
    border: "1px solid " + t.border,
    borderRadius: t.radius,
    display: "flex",
    overflow: "hidden"
  }}>
                    <div style={{
    flex: 1,
    padding: 6,
    display: "flex",
    flexDirection: "column",
    gap: 3,
    lineHeight: 1
  }}>
                      <span style={{
    fontSize: 9
  }}>Arrive by</span>
                      <span style={{
    fontSize: 11,
    whiteSpace: "nowrap"
  }}>{fmt(START)}</span>
                    </div>
                    <div style={{
    flex: 1,
    padding: 6,
    display: "flex",
    flexDirection: "column",
    gap: 3,
    lineHeight: 1,
    borderLeft: "1px solid " + t.border
  }}>
                      <span style={{
    fontSize: 9
  }}>Return by</span>
                      <span style={{
    fontSize: 11,
    whiteSpace: "nowrap"
  }}>{fmt(endDate)}</span>
                    </div>
                  </div>

                  {}
                  <div>
                    <span style={label}>Add-ons</span>
                    <div style={{
    border: "1px solid " + t.border,
    borderRadius: t.radius,
    background: "#ffffff",
    overflow: "hidden",
    display: "flex",
    flexDirection: "column"
  }}>
                      {ADDONS.map((a, i) => {
    const on = !!addons[a.id];
    return <button key={a.id} type="button" aria-pressed={on} aria-disabled={a.required || undefined} onClick={() => toggleAddon(a)} style={{
      display: "flex",
      alignItems: "center",
      gap: 6,
      padding: 6,
      lineHeight: 1,
      background: "transparent",
      border: 0,
      borderTop: i ? "1px solid " + t.border : 0,
      cursor: a.required ? "default" : "pointer",
      width: "100%",
      color: t.text
    }}>
                            <span style={{
      flex: "none",
      width: 16,
      height: 16,
      borderRadius: "50%",
      border: "1px solid " + (on ? a.required ? t.subdued : t.accent : t.border),
      background: on ? a.required ? t.subdued : t.accent : "transparent",
      display: "grid",
      placeItems: "center",
      color: "#ffffff",
      transition: "background-color 150ms ease, border-color 150ms ease"
    }}>
                              <svg viewBox="0 0 10 10" fill="none" width="10" height="10" style={{
      opacity: on ? 1 : 0
    }}>
                                <path d="M1.5 5.5l2.3 2.3L8.5 2.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                              </svg>
                            </span>
                            <span style={{
      flex: 1,
      minWidth: 0,
      display: "flex",
      flexDirection: "column",
      gap: 4
    }}>
                              <span style={{
      display: "inline-flex",
      alignItems: "center",
      gap: 6,
      fontSize: 11
    }}>
                                {a.title}
                                {a.required && <span style={{
      fontSize: 9,
      textTransform: "uppercase",
      letterSpacing: "0.04em",
      color: t.subdued
    }}>
                                    Required
                                  </span>}
                              </span>
                              {a.desc && <span style={{
      fontSize: 10,
      color: t.subdued
    }}>{a.desc}</span>}
                            </span>
                            <span style={{
      flex: "none",
      whiteSpace: "nowrap",
      fontSize: 11
    }}>{money(a.price)}</span>
                          </button>;
  })}
                    </div>
                  </div>

                  {}
                  <div>
                    <div style={{
    borderTop: "1px solid " + t.border,
    paddingTop: 6,
    display: "flex",
    flexDirection: "column",
    gap: 5
  }}>
                      <span style={line}>
                        <span>
                          {money(perDay)}/day x {PERIODS[period].days} days
                        </span>
                        <span>{money(PERIODS[period].price)}</span>
                      </span>
                      {ADDONS.filter(a => addons[a.id]).map(a => <span key={a.id} style={line}>
                          <span>{a.title}</span>
                          <span>{money(a.price)}</span>
                        </span>)}
                    </div>
                    <div style={{
    borderTop: "1px solid " + t.border,
    marginTop: 6,
    paddingTop: 6
  }}>
                      <span style={{
    ...line,
    fontWeight: 550
  }}>
                        <span>Total</span>
                        <span>{money(total)}</span>
                      </span>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <button type="button" className="sc-cpdp-cta">
              Add to cart
            </button>
          </div>
        </div>

          <div className="sc-cpdp-desc" aria-hidden="true">
            <div>
              <h4>Details</h4>
              <p>
                A forgiving all-mountain ski with a poplar core and a 92mm waist, paired with adjustable poles.
                Sized to your height and weight at checkout.
              </p>
            </div>
            <div>
              <h4>What's included</h4>
              <ul>
                <li>Skis with bindings, tuned and waxed before every rental</li>
                <li>Adjustable poles</li>
                <li>Padded ski bag for transport</li>
              </ul>
            </div>
            <div>
              <h4>How rental works</h4>
              <p>
                Your set arrives by the first day of your rental period. Return it by the last day using the
                prepaid label in the bag, or drop it at any of our stores.
              </p>
            </div>
          </div>
        </div>
        </div>
      </div>
    </div>;
};

<Info>
  Supercycle works with your theme's product form out of the box. If your theme uses custom markup for the product form or the variant input, see [Methods app block troubleshooting](/developers/troubleshooting/method-app-block) to help Supercycle detect and control those elements.
</Info>

The Methods app block adds a product's methods to the product page: rental periods and dates for calendar, pricing groups for subscription, credits for membership, and a price for resale. It takes over the theme's add to cart button so a customer can only add a valid selection to the cart.

<Frame type="glass" caption="The Methods app block on a calendar rental product. Pick a rental period and the dates and total follow.">
  <CalendarRentalPdp />
</Frame>

***

## How it works

The block controls your product form through a component called ProductContextSync, which detects, watches, and controls the form.

<Steps>
  <Step title="Sync the variant ID">
    It watches your theme's variant input and keeps it in step with the active variant.
  </Step>

  <Step title="Inject hidden inputs">
    It adds the rental data the cart needs, such as the selling plan and the [line item properties](/developers/line-items/cycle-line-item-properties), to your form.
  </Step>

  <Step title="Control the button state">
    It enables or disables the button from the rental validation. The button stays disabled when:

    * No method is selected
    * The product is out of stock
    * The customer doesn't have enough credits
    * Required [terms and conditions](/documentation/configuration/risk/terms-and-conditions) haven't been accepted
  </Step>
</Steps>

<Note>
  The takeover is non-destructive. It only adds hidden inputs and toggles the button state, and doesn't change your theme's markup. Supercycle uses a `MutationObserver` to keep the button state even when other scripts change it, and supports AJAX carts by injecting the rental data before submission.
</Note>

***

## Item condition options

The **Display item condition options** block setting adds an item condition picker above the methods, so customers choose the condition they want before they pick a method. It mirrors **Display duration options**, with a checkbox to turn it on and an **Item condition options display** radio for a **Radio** or **Select** layout.

The picker lists only the conditions marked **Show on storefront** under <Icon icon="shopify" iconType="solid" /> **[Custom data](https://admin.shopify.com/apps/supercycle/settings/custom_data)** in the Supercycle admin. With none marked, the picker renders nothing, so the setting is safe to leave on. See [Item conditions](/documentation/manage/inventory/item-conditions#show-conditions-on-the-storefront) for the admin side.

Nothing is selected until the customer picks a condition. From then on the pick joins variant and market as an option filter:

* Options whose **Apply to specific item conditions** list excludes the pick are hidden.
* Options that apply to all conditions always show.
* A method left with no visible options renders as unavailable, the same as a method with no inventory.
* On the calendar method, a pick that hides the selected duration moves the selection to the visible duration of the same length, or clears it, so a hidden option's selling plan is never submitted.

<Note>
  The picked condition is a display filter. It isn't sent with the rental, so an option that applies to all conditions can still be fulfilled with an item of any condition.
</Note>

***

## Date picker blocked dates

You manage storefront calendar rules from <Icon icon="shopify" iconType="solid" /> **[Channels](https://admin.shopify.com/apps/supercycle/settings/channels)** under **Online store**. See [Date picker blocked dates](/documentation/online-store/date-picker-blocks) for the block types, start and end targeting, and examples.

Those rules feed the block's calendar on the online store. When a customer picks dates, rentals whose start or end lands on a blocked rule are rejected, and duration options that would land on a blocked boundary are disabled.

<Note>
  Date picker blocked dates only affect which dates are selectable on the storefront calendar. To remove availability for a product, variant, or item across the store, use [Blocked dates](/documentation/manage/inventory/blocked-dates). [Opening hours](/documentation/configuration/logistics/opening-hours) can also block pickup and drop-off dates when time selection is on.
</Note>

***

## Legacy theme JSON matchers <Badge color="gray" size="sm">Deprecated</Badge>

The block still exposes the **Unavailable start dates** and **Unavailable end dates** theme settings. Both accept DayPicker matcher JSON and apply on top of the admin rules, so existing JSON keeps working. Use [Date picker blocked dates](/documentation/online-store/date-picker-blocks) for new rules.

* **Unavailable start dates.** Blocks dates from being chosen as a rental start date.
* **Unavailable end dates.** Blocks dates from being chosen as a rental end date, independently of start dates.

Both fields accept the same JSON object or array. Days of the week are numbered `0` for Sunday through `6` for Saturday.

### Matcher examples

Paste one of these into **Unavailable start dates** or **Unavailable end dates**.

<CodeGroup>
  ```json All Mondays theme={null}
  {"dayOfWeek": [1]}
  ```

  ```json Saturdays and Sundays theme={null}
  {"dayOfWeek": [0, 6]}
  ```

  ```json A specific date theme={null}
  {"from": "2026-01-01", "to": "2026-01-01"}
  ```

  ```json A date range theme={null}
  {"from": "2025-12-22", "to": "2025-12-27"}
  ```

  ```json Several rules combined theme={null}
  [
    {"dayOfWeek": [1]},
    {"dayOfWeek": [0, 6]},
    {"from": "2026-01-01", "to": "2026-01-01"},
    {"from": "2025-12-22", "to": "2025-12-27"}
  ]
  ```
</CodeGroup>

### Format reference

* **Day of week.** `{"dayOfWeek": [0, 1, 2]}` blocks those days every week.
* **Single date.** `{"from": "YYYY-MM-DD", "to": "YYYY-MM-DD"}` with the same date in both.
* **Date range.** `{"from": "YYYY-MM-DD", "to": "YYYY-MM-DD"}` blocks every date in the range.
* **After a date.** `{"after": Date}` blocks every date after it.
* **Several matchers.** An array `[...]` combines rules.

### Block dates dynamically

To block dates by a rolling rule, for example to cap bookings at 6 weeks ahead, add this script to your product template or a custom Liquid block:

```html Rolling booking window theme={null}
<script>
    const weeksToBlock = 6;
    const blockFrom = new Date();
    blockFrom.setDate(blockFrom.getDate() + weeksToBlock * 7);
    window.supercycleDisabledMatchers = [{after: blockFrom}];
</script>
```

This blocks every date more than 6 weeks from today. Change `weeksToBlock` to move the window. `window.supercycleDisabledMatchers` applies to both start and end dates.

<Tip>
  Put the script in a custom Liquid block rather than the main product template to give different products or product templates their own booking window.
</Tip>

***

## Add the block to a custom or legacy theme

If your theme doesn't support app blocks, add the methods component to the product template by hand.

<Steps>
  <Step title="Open the product template">
    On <Icon icon="shopify" iconType="solid" /> **[Themes](https://admin.shopify.com/themes)**, open your theme's **... > Edit code** menu, then open the file your theme uses for the product page: `sections/main-product.liquid`, `sections/product-template.liquid`, or `templates/product.liquid` on very old themes.
  </Step>

  <Step title="Find the title and the form">
    Find where the product title and the add to cart button are rendered. The methods component goes between them.
  </Step>

  <Step title="Paste the methods component">
    Add the snippet at that spot.

    ```html Product template theme={null}
    <x-methods
      data-settings='{
        "default_method": "calendar",
        "item_condition_options": false,
        "item_condition_options_display": "radio",
        "subtitle_alignment": "right",
        "calendar_price_display": "price_per_day/from_price",
        "calendar_dropdown_alignment": "left",
        "calendar_duration_options": false,
        "calendar_unavailable_start_dates": "",
        "calendar_unavailable_end_dates": "",
        "subscription_price_interval": "day",
        "subscription_price_interval_count": 1,
        "subscription_price_format": "from_price",
        "pricing_groups_display": "radio",
        "membership_join_button_url": null,
        "custom_css": ""
      }'
      data-product-metafields="{{ product.metafields.supercycle | json | escape }}"
      data-customer-metafields="{{ customer.metafields.supercycle | json | escape }}"
      data-initial-variant-id="{{ product.selected_or_first_available_variant.id }}"
    ></x-methods>
    ```
  </Step>

  <Step title="Save and test">
    Save, then preview a product with methods turned on. Change variants to confirm the price and options update.
  </Step>
</Steps>

***

## Methods app block troubleshooting

If the block doesn't appear, the button stays disabled, or the price doesn't follow the variant, see [Methods app block troubleshooting](/developers/troubleshooting/method-app-block). It covers variant input and add to cart form detection, empty blocks, and price updates.

***

## Methods app block FAQs

<AccordionGroup>
  <Accordion title="Can I style the Methods app block?">
    Yes. Use the `custom_css` setting in `data-settings` for small overrides. For larger changes, target the block's CSS classes from your theme's stylesheet.
  </Accordion>

  <Accordion title="Can I target a specific method option?">
    Yes. Each option element exposes its admin name as `data-supercycle-option-name`, so you can hide or restyle specific options from CSS or JavaScript. See [Target method options by name](/developers/code-snippets/target-method-options).
  </Accordion>
</AccordionGroup>
