A space to discuss online store customization, theme development, and Liquid templating.
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:
Solved! Go to the solution
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.
Hey buddy, Have you solved your problem if you're solved please let me know how you do that
Hey I just ran into this issue as well, is there any fix?
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.
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:
<div id="container"></div>
{% schema %}
{
"name":"React Block",
"target":"section",
"javascript":"bundle.js",
"settings":[
{
"type":"color",
"id":"color_id",
"label":"Color",
"default":"#ff0000"
}
]
}
{% endschema %}
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.
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?
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.
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:
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.
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.
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 ..
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.
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
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.
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
Did you find a solution for the multiple blocks?
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.
If I am following correctly you could utilize Snippets and possibly pass their parent divs different data via html data attributes.
Good solution, but I read the theme app extension document, there are some file and content size limits:
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.
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.
Wow, you are right.
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?