Re: Use React in app block theme extension

Solved

Use React in app block theme extension

CymbalOfPeas
Visitor
2 0 2

Hello, I've just started getting into shopify development and completed Build App Example tutorial. It was a great tutorial, but really only covered the merchant back office flow. The app I'd like to build interacts with the online store. I've read through the docs and started using app blocks. 

 

My practice app is very simple. I have an input field on the product page, and I'd just like to sync the data to a draftOrder or checkout flow. I'm planning to post this data to an endpoint on submit. The part that's confusing me is the assets in my extension. I understand how to link schema settings and css in liquid, but is there no way to use React? It seems like I need to use vanilla javascript, and add that file to /assets/my-app.js.

 

I'm not new to development, but I am new to shopify. Maybe I'm missing something, but this doesn't feel right needing to import javascript like this? It also seems like it's not encouraged to use ScriptTag anymore. Any clarification or resources on this would be much appreciated!

 

Just looked into Dawn a bit more and seems like I'll have to go vanilla js:
https://github.com/Shopify/dawn/tree/main/assets 

 

I've also read through:

Accepted Solution (1)

ozzyonfire
Shopify Partner
49 2 17

This is an accepted solution.

Just in case you haven't solved this yet. Is is possible to use React within an extension. 

 

You can use tools like webpack and babel to bundle up your react app into a single file (i.e. bundle.js). Then in your block, just include that one file. 


Your app-block.liquid file may look something like this.

<div id="container"></div>

{% schema %}
  {
    "name": "React Block",
    "target": "section",
    "javascript": "bundle.js",
    "settings": []
  }
{% endschema %}

And then in your `src` directory, you can create a react app file, like index.js

import React from 'react';
import { createRoot } from 'react-dom/client';

const container = document.getElementById('container');
const root = createRoot(container!);

root.render(<h1>Hello World!</h1>);

You will need to configure webpack to bundle react apps appropriately, but there are plenty of tutorials out there on how to do that.

View solution in original post

Replies 70 (70)
Ken38
Shopify Partner
6 0 2

Hey buddy, Have you solved your problem if you're solved please let me know how you do that

Andrew147
Shopify Partner
4 0 0

Hey I just ran into this issue as well, is there any fix?

Andrew147
Shopify Partner
4 0 0

For anyone looking - I ended up abandoning this approach and just inserting my React app as an iframe while hosting it externally. Shopify needs better documentation on how to build with React in a theme. 

manfa
Shopify Partner
4 0 2

Everything seems to be great, but I'm wondering if there is a possibility to directly use block settings and translations located in the /locales directory in theme-app-extensions in the React code?

 

For example:

  1. I would like to be able to define the color of a certain element.
  2. I would like to use the translation .json files located in the /locales directory.
<div id="container"></div> 

{% schema %}
{
"name":"React Block",
"target":"section",
"javascript":"bundle.js",
"settings":[
{
"type":"color",
"id":"color_id",
"label":"Color",
"default":"#ff0000"
}
]
}
{% endschema %}

 

 

Jamflynt
Shopify Partner
38 0 20

I may be misunderstanding your question but to define the color of a certain element you could just use App Block Schema's and then pass the settings into the react app via data attributes on the root div. We've used this to accomplish several settings on within a React App. 

As for the translations, I've not done this but I don't see why you wouldn't be able too. I'd imagine it'd be part of the settings somewhere. 

manfa
Shopify Partner
4 0 2

Thanks @Jamflynt for the answer. Yes, it seems that it can be achieved by passing the data in data-attributes. I will test it. It would probably look something like this?

 

<div
id="react-container"
data-theme-color="{{ settings.color_id }}"
data-theme-title="{{ 'title' | t }}"
data-theme-label="{{ 'label' | t }}"
data-some-other-translate="{{ 'otherTranslate' | t }}"
>
</div>

{% schema %}
{
"name":"React Block",
"target":"section",
"javascript":"bundle.js",
"settings":[
{
"type":"color",
"id":"color_id",
"label":"Color",
"default":"#ff0000"
}
]
}
{% endschema %}

 

But I have a second question. How to use React in case we have several Liquid blocks? I understand that for each block it would be a kind of React micro-frontend each bundled to separate file? How would that work?

Jamflynt
Shopify Partner
38 0 20

Looks good to me. Only thing I see is here: 

data-theme-color="{{ settings.color_id }}"

Should look something like this in my experience: 

data-theme-color="{{ block.settings.color_id }}"

Anytime you reference an App Block setting you just need `block` in front of it. 

As to your second question, we've had success having our React App living in a separate folder outside of the extensions folder (Shopify is very picky on its structure) and creating an npm command to compile and push the bundled app to the appropriate locations inside of the extensions folder. 

Then just continue to add other Liquid blocks as you see fit and need. Just be aware that for App Extensions, Shopify has a limit of 10MB for Liquid files across the whole extensions folder. 

manfa
Shopify Partner
4 0 2

To clarify, do you mean that you have one React App situated outside the extensions directory? I'm having trouble understanding how this setup would function with multiple Liquid files.

 

My aim is to create a variety of independent Liquid blocks that can be integrated into different pages. Consequently, in my opinion, each block should be associated with a distinct React App, or at the very least, a different React Component.

 

For instance:

  1. Star Rating Liquid (React App A) -> Implemented on page A
  2. Additional Customer Information (React App B) -> Implemented on page B
  3. Customer Custom Coupons (React App C) -> Implemented on page C

These are merely illustrative examples, but I'm eager to understand if this approach is correct and it should be achieved with only Components in one React App.

 

Shopify has a limit of 10MB for Liquid files across the whole extensions folder. 

Yes, we are aware of Shopify's limits for this. We have small amount of functionalities, so we should not exceed this limit.

 

Jamflynt
Shopify Partner
38 0 20

For our purposes we are only using one React app that is populating one App block so yeah we have only one situated outside of the extensions folder. We also have several other App blocks inside of that Theme-app-extension that are not talking to a React app. 

Keep in mind, you can only have 1 theme-app-extension per App but that theme-app-extension can have up to 25 App blocks in the Blocks folder. 

If you had multiple apps, I'd assume what you have laid out would work. You would have each one build and populate (something you would set up in your package.json file) an individual App (Liquid) block in the Blocks folder in your extensions directory within the Shopify App. Shopify does not allow anything outside of this extensions file structure to live inside of the extensions/theme-app-extensions folder, so just be aware that the apps would have to live somewhere outside of that. 

Also, unless I am misunderstanding, you could probably get away with having a single react app that renders a specific component depending on where you've embedded the block in a Shopify page. You'd need to research that though. 

mqasim
Shopify Partner
4 0 0

i read all the conversation but still m confused  kindly guide me ..

 i have created a remix app using the cli3 and after that i also created a theme extension as well which i a block app to render a button in the product page and in the remix app i created a model using the polaris and i want to show the model which i created in the remix app to be shown when the user click on the button which i on the prouduct page here is the SS of what i did till now ..

mqasim_0-1701703710265.pngmqasim_1-1701703736990.png

 

mqasim_2-1701704317271.png

 

 

Jamflynt
Shopify Partner
38 0 20

Keep in mind Polaris is for Admin experiences only in Shopify, not client side/customer facing experiences. The base React stuff that is created when you create the App template is for this Admin experience and cannot be used in the theme-app-extension.

To get a modal to show up after clicking a button on your PDP, you'll have to create and compile a separate/new React application that works within the confines of your store or use JavaScript and Liquid inside the extension. The later is what is intended to be used with Theme-app extensions so if you can make that work, that would be the way to go.

mqasim
Shopify Partner
4 0 0

i have created the theme app extension (block app)  and with the help of extension I'm showing  a button with the label of " Cash On delivery  " and i want to show the model with the form which i have created in the app , ok i got it that polaris is for the admin , but can you please guide me in a simple way or get any reference , I'm creating a cash on delivery app 

Jamflynt
Shopify Partner
38 0 20

I'm not totally clear on what you're asking, but it sounds like you'll want to recreate the form you created for the admin in the app block to get it to show up. Beyond that, familiarize yourself with the theme-app extension framework and the rest of the documentation surrounding apps, as well as the various API's you'll have access too to make your block work. 

Also keep in mind that Shopify has a Cash On Demand option available as an option in their checkout. You may also want to familiarize yourself with Shopify Functions and Checkout Extensions. This may be better suited to what you are trying to do.

densekernel
Shopify Partner
9 0 0

This is very similar to the use case - I am trying to solve.

 

I am leaning towards using one React app for both liquid blocks as they will both use shared components.

 

Otherwise, if multiple React apps are required then they need to be able to import the shared parts from a common source but that adds a lot of complexity to the development workflow:

 

- Develop component in library

- Develop Reacts apps using components from library

- Bundle React apps to multiple output JS files

- Finally consume the bundles in the relevant liquid files

densekernel
Shopify Partner
9 0 0

Did you find a solution for the multiple blocks?

jedi1205
Shopify Partner
1 0 0

Hi @Jamflynt and DenseKernel I also wish to know about what if i wish to make multiple embeds on say same page. Like different liquid files would have different bundles? and if say a single liquid file is assoicated in multiple places how would i differentiate the divs for them and how would i fetch data for different blocks if i need to get data for different ids.

Jamflynt
Shopify Partner
38 0 20

If I am following correctly you could utilize Snippets and possibly pass their parent divs different data via html data attributes.

NickShi
Shopify Partner
26 3 3

Good solution,  but I read the theme app extension document, there are some file and content size limits: 

 

theme-app-extension.jpg

https://shopify.dev/docs/apps/online-store/theme-app-extensions/extensions-framework#file-and-conten...

 

But for react V18.2.0, React(7KB) + React-dom(132KB) = 139KB,  in other words the bundle.js size will always oversize of 15KB of "Size of each local file" enforce limit. I think if we used React&React-dom in our public app(extension),  the app store will rejected it.

 

Not to know is there any app(extension) used this solution to pass the app store review, glad to hear it.

- If helpful then please Likes and make it as a Solution.
- If you want to develop a store/app, or need custom software development services Email Me
Mittlus
Shopify Partner
4 0 1

I think you misread the app content column, its "locale" not "local" file, which are the language translation files in your 'extensions > locales' folder. The max. size for compressed JS of 10 KB is only suggested, so ich you don't extend the max. size for all extension files of 10 MB you should be fine.

NickShi
Shopify Partner
26 3 3

Wow, you are right. 

- If helpful then please Likes and make it as a Solution.
- If you want to develop a store/app, or need custom software development services Email Me
danny_boris
Shopify Partner
10 0 1

With this approach, updating schemas settings will cause shopify storefront to reload.

Meaning if I wish to modify some text, every keystroke (or few keystrokes) will reload the page.

I passed the block.settings object via <div id="root" data-settings={{ block.settings }} />
and it does work when fetching this attribute from within the app.

But the refresh makes user exp so poor.

Is there a way around it?