# Alpine.js and Blade/ACF-composer

**URL:** https://discourse.roots.io/t/alpine-js-and-blade-acf-composer/23756
**Category:** sage
**Tags:** acf, alpinejs, gutenberg
**Created:** 2022-08-17T08:26:47Z
**Posts:** 14

## Post 1 by @cim — 2022-08-17T08:26:47Z

Is it possible and/or good practice to use Alpine.js in Blade templates for ACF Blocks (made with ACF Composer)?

I used Alpine.js in normal Blade templates before, but using it Blade templates for ACF blocks is giving me a lot of troubles so far

Here is one example:

This works:  
`<div x-screen="topmargin = Math.floor((( $width < 1400 ? $width : 1400 ) / Math.sin(85.8 * Math.PI/180)) * (Math.sin(4.2 * Math.PI/180)))">`

But if I use `$width >` instead of `$width <` the parser chokes on it. Also got errors when using `$watch`

In the editor the block doesn’t work at all when I add Alpine code to the template, even though I import Alpine in editor.js the same way as I do in app.js.

If people are interested in the exact errors let me know.

---

## Post 2 by @joshf — 2022-08-17T13:53:02Z

I typically filter out Alpine code from running in the editor itself and keep it frontend only.

I do this either by wrapping Alpine logic in `@if (! $block->preview)` or by using a [preview view](https://github.com/Log1x/acf-composer#block-preview-view) for more complicated blocks.

---

## Post 3 by @cim — 2022-08-17T14:08:04Z

Thanks. conditionals and the separate preview are useful yes.

Do you filter out Alpine because you found it problematic too? I was kind of hoping to mirror the front-end in the editor, but maybe I want too much;)

Also wondering why I get those parsing errors on the front-end with the example I gave

---

## Post 4 by @joshf — 2022-08-17T17:14:42Z

Yeah, most of my Alpine functionality doesn’t need to operate in the editor. Things like sorting posts, opening menus or accordions, etc. I don’t really want the editor to be interactive beyond the editing portion.

In general, those are the requirements I work with… but that could change depending on the specific use case.

My guess as to the syntax breaking the editor would be that it’s attempting to parse the view as jsx?. Is the `supports['jsx']` option for that particular block set to `false`? Totally spitballing but might be worth a look.

---

## Post 5 by @UnlocDavid — 2022-08-18T09:05:25Z

Yep, disabling JSX works wonders for Alpine.js support in the editor.

I’ve also ran into trouble with shorthand attributes, so `@click="..."` wouldn’t work, but `x-on:click="..."` did.

---

## Post 6 by @cim — 2022-08-18T09:46:18Z

> [@joshf](#):
>
> My guess as to the syntax breaking the editor would be that it’s attempting to parse the view as jsx?.

Thanks, hadn’t thought of that

For my case it doesn’t make a difference though. Didn’t try the editor yet, but I still get this error on the front-end when using `>` instead of `<`  
`Uncaught SyntaxError: illegal character U+2018`.

Note it’s all fine in a regular blade template.

You both use acf-composer right? Trying to narrow down what the problem is

---

## Post 7 by @UnlocDavid — 2022-08-18T14:58:50Z

Not sure what is happening, I’ve tried your code (without `x-screen`, I don’t use that Alpine plugin) and it just works. So maybe the problem is with the plugin.

Maybe you can abstract the code in the `x-screen` attribute to a function call?

Also I just Googled the unicode character and it’s this: [“‘” U+2018 Left Single Quotation Mark Unicode Character](https://www.compart.com/en/unicode/U+2018) So maybe you just have a wrong opening quote or something?

---

## Post 8 by @cim — 2022-08-18T15:50:47Z

Thanks for helping.  
It is weird.  
I removed that plugin, then created a standard block with acf-composer, disabled jsx support and added this to the blade template:

```
<div class="{{ $block->classes }}" 
  x-data="{topmargin: 0}" x-init="topmargin=(1 < 2 ? 1 : 2)"
  >
```

When I replace `<` with `>` I get the error again, but this time the Right Double Quotation Mark:

`Uncaught SyntaxError: illegal character U+201D`

---

## Post 9 by @joshf — 2022-08-18T18:32:31Z

I just dropped your snippet into a block with JSX disabled and didn’t receive a parse error. (And yep, using `acf-composer`.)

Enabling JSX does throw an error and the block doesn’t render at all.

Sorry! Wish I could replicate.

---

## Post 10 by @cim — 2022-08-18T20:16:23Z

Thanks anyway. It is good to know that it _should_ work.

I guess it may have to do with Acorn and/or the fact that I have Acorn installed as a plugin (v2.1.2)

Edit:

> [@joshf](#):
>
> I just dropped your snippet into a block with JSX disabled and didn’t receive a parse error.

Just to be 100% clear: in the snippet `<` should be replaced with `>` to produce the error. Also the above block works for me in the editor (when disabling jsx, so thanks for that), the error occurs on the front-end.

---

## Post 11 by @grahammtbr — 2022-08-24T18:09:46Z

I went through this a year ago, it has to do with ACF’s parsing of the view when using JSX, nothing to do with Acorn. To fix you need to wrap anything with “illegal” characters with esc\_attr when enabling JSX. Or move the JS to a file and just call the function from x-data, x-init, etc.

```
<div class="{{ $block->classes }}" 
  x-data="{topmargin: 0}" x-init="<?= esc_attr('topmargin=(1 < 2 ? 1 : 2)') ?>"
>
```

---

## Post 12 by @cim — 2022-08-25T07:45:13Z

Thanks! Is still don’t know why I get these errors in my basic example with jsx disabled (and joshf not). But I can confirm wrapping with esc\_atrr does work (also with my non-jsx example).

> [@grahammtbr](#):
>
> it has to do with ACF’s parsing

That is also good to know.

---

## Post 13 by @chrillep — 2024-10-16T09:34:59Z

logix has fixed it by

adding  
alpine-support.blade.php

```
<script type="text/javascript">
    acf.addFilter('acf_blocks_parse_node_attr', (current, node) => node.name.startsWith('x-') ? node : current);
</script>
```

```
add_filter('acf/input/admin_footer', function () {
            echo view('fastlane::components.alpine-support')->render();
        });
```

refs:

> <https://github.com/Log1x/acf-composer/blob/e17b51a6afe4f2a9273de4b568160e55248836d1/resources/views/alpine-support.blade.php>

[https://github.com/Log1x/acf-composer/blob/e17b51a6afe4f2a9273de4b568160e55248836d1/src/AcfComposer.php#L104-L106](https://github.com/Log1x/acf-composer/blob/e17b51a6afe4f2a9273de4b568160e55248836d1/src/AcfComposer.php#L104-L106)

- [Enhancement - The internal ACF Blocks template attribute parser function `parseNodeAttr` can now be shortcut with the new `acf_blocks_parse_node_attr` filter.](https://www.advancedcustomfields.com/blog/acf-6-2-1/#:~:text=Enhancement%20%E2%80%93%20The%20internal%20ACF%20Blocks%20template%20attribute%20parser%20function%20parseNodeAttr%20can%20now%20be%20shortcut%20with%20the%20new%20acf_blocks_parse_node_attr%20filter)

from acf js

```
/**
   * Converts the given attribute into a React friendly name and value object.
   *
   * @date	19/05/2020
   * @since	5.9.0
   *
   * @param	obj nodeAttr The node attribute.
   * @return	obj
   */
  function parseNodeAttr(nodeAttr) {
    let name = nodeAttr.name;
    let value = nodeAttr.value;

    // Allow overrides for third party libraries who might use specific attributes.
    let shortcut = acf.applyFilters('acf_blocks_parse_node_attr', false, nodeAttr);
    if (shortcut) return shortcut;
    switch (name) {
      // Class.
      case 'class':
        name = 'className';
        break;

      // Style.
      case 'style':
        const css = {};
        value.split(';').forEach(s => {
          const pos = s.indexOf(':');
          if (pos > 0) {
            let ruleName = s.substr(0, pos).trim();
            const ruleValue = s.substr(pos + 1).trim();

            // Rename core properties, but not CSS variables.
            if (ruleName.charAt(0) !== '-') {
              ruleName = acf.strCamelCase(ruleName);
            }
            css[ruleName] = ruleValue;
          }
        });
        value = css;
        break;

      // Default.
      default:
        // No formatting needed for "data-x" attributes.
        if (name.indexOf('data-') === 0) {
          break;
        }

        // Replace names for JSX counterparts.
        name = getJSXName(name);

        // Convert JSON values.
        const c1 = value.charAt(0);
        if (c1 === '[' || c1 === '{') {
          value = JSON.parse(value);
        }

        // Convert bool values.
        if (value === 'true' || value === 'false') {
          value = value === 'true';
        }
        break;
    }
    return {
      name,
      value
    };
  }
```

---

## Post 14 by @alexgm — 2025-01-19T22:42:15Z

For those in same situation, dont use the alpine shorthands and it will work fine with log
