---
gid: 91696086-8c78-455b-af68-5306f38f4615
title: Build an admin block
description: Learn how to create block extensions on resource pages in the Shopify admin.
---

<Repo extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react" />

{/* TODO */}
{/* <Repo
  extension="javascript"
  href="https://github.com/Shopify/example-admin--action-and-block--js"
/> */}

<Picker name="extension">
  <PickerOption name="react" />
  {/* <PickerOption name="javascript" /> */}
</Picker>

<Overview>
  This guide is the second part in a five-part tutorial series on how to build a feature using admin action and block extensions. Before starting this guide, you'll need to build or copy the admin action extension from the [build an admin action tutorial](/docs/apps/build/admin/actions-blocks/build-admin-action).

  So far, you've created an action extension that enables buyers to create issues for a product. However, merchants need an easy way to see them. This guide demonstrates how to create an admin block extension to display buyer-created issues for a product.

  ![The new block extension at the bottom of the page. Two issues, which have been created with the action, display.](/assets/admin/admin-actions-and-block/build-an-admin-block/block-on-page-csb.png)

  ## What you'll learn

  In this tutorial, you'll learn how to do the following tasks:

  - Create an admin block extension that displays on the product details page

  - Fetch information to populate the extensions's initial state

  - Connect the extension to the Shopify admin's contextual save bar when gathering input, to make editing pages seamless

  - Run the extension locally and test it on a development store
</Overview>

<Requirements>
  <Requirement href="https://www.shopify.com/partners" label="Create a Partner account" />

  <Requirement href="/docs/apps/tools/development-stores#create-a-development-store-to-test-your-app" label="Create a development store" />

  <Requirement href="/docs/apps/build/scaffold-app" label="Scaffold an app">
    Scaffold an app with the `write_products` access scope that uses [Shopify CLI 3.75 or higher](/docs/api/shopify-cli#upgrade).

    - If you created a Remix app, then the `write_products` access scope is automatically granted to your app.
    - If you created an extension-only app, then you need to explicitly grant the `write_products` access scope to your [custom app](/docs/apps/auth/access-token-types/admin-app-access-tokens#changing-api-scopes).
    - Add a product to your development store. The product should not have any custom variants at the start of this tutorial.
  </Requirement>

  <Requirement href="/docs/apps/admin/admin-actions-and-blocks/build-an-admin-action" label="Build an admin action">
    Complete or copy the code from the [build an admin action](/docs/apps/build/admin/actions-blocks/build-admin-action) tutorial.
  </Requirement>

</Requirements>

<StepSection>
  <Step>
    ## Create a new extension

    Use Shopify CLI to [generate starter code](/docs/api/shopify-cli/app/app-generate-extension) for your block extension.

    1.  Navigate to your app directory:
        <Codeblock terminal>
          ```bash
          cd <directory>
          ```
        </Codeblock>

    2.  Run the following command to create a new admin block extension:

        <Codeblock terminal>
          ```bash
          shopify app generate extension --template admin_block --name issue-tracker-block --flavor react
          ```
        </Codeblock>

        The command creates a new extension template in your app's `extensions` directory with the following structure:

        <Codeblock title="Admin block structure">
          ```text
            extensions/issue-tracker-block
            ├── README.md
            ├── locales
            │   ├── en.default.json // The default locale for the extension
            │   └── fr.json // The French language translations for the extension
            ├── package.json
            ├── shopify.extension.toml // The config file for the extension
            └── src
                └── BlockExtension.jsx // The code that defines the block's UI and behavior
          ```
        </Codeblock>
  </Step>

  <Step>
    ## Write the extension's UI

    Complete the following steps to write the extension's UI and display initial data:

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/shopify.extension.toml" tag="block-extension.configuration"/>

      ### Review the configuration

      The extensions `.toml` file stores the extension's static configuration. To have the issue tracker display on product detail pages, set the target to `admin.product-details.block.render`.

      <Resources>
        [admin.product-details.block.render](/docs/api/admin-extensions/latest/api/extension-targets#extensiontargets-propertydetail-adminproductdetailsblockrender)
      </Resources>
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/locales/en.default.json" />

      ### Update title

      To update the display name when users select the action from the menu, in locale files edit the `name` value.  The block extension uses the i18n API to translate strings so that your app is more accessible to a wider audience. This API gives you access to the strings stored in the locale files, and automatically chooses the correct string for the current user's locale.

      <Resources>
        [i18n API](/docs/api/admin-extensions/api/block-extension-api#blockextensionapi-propertydetail-i18n)
      </Resources>
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/locales/fr.json" />

      ### Translate title

      Optionally translate your title to French.
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.create-ui-one"/>

      ### Use components to create the extension's UI

      Admin UI extensions are rendered using [Remote UI](https://github.com/Shopify/remote-dom/tree/remote-ui), which is a fast and secure remote-rendering framework. Because Shopify renders the UI remotely, components used in the extensions must comply with a contract in the Shopify host. We provide these components through the admin UI extensions library.

      <Resources>
        [Admin UI extensions components](/docs/api/admin-extensions/components)
      </Resources>
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.create-ui-two"/>

      ### Note the export

      You can view the source of your extension in the `src/BlockExtension.jsx` file. This file defines a functional React component that's exported to run at the extension's target. You can create the extension's body by importing and using components from the `@shopify/ui-extensions-react/admin` package.

      <Notice type="warning" title="Caution">
        The extension point in the component export must match the extension point that's defined in your `.toml` file, or the extension won't render.
      </Notice>

    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.create-ui-three"/>

      ### Render a UI

      To build your block's UX, return some components from `src/BlockExtension.jsx`. You'll create a simple UI to list out your QR codes.
    </Substep>
  </Step>

  <Step>
    ## Write the extension logic and connect to the GraphQL Admin API

    After defining the extension's UI, use standard React tooling to write the logic that controls the extension.

    When you're writing extensions, you don't need proxy calls to the [GraphQL Admin API](/docs/api/admin-graphql) through your app's backend. Instead, your extension can use [direct API access](/docs/api/admin-extensions#directapiaccess) to create requests directly using `fetch`. This helps extensions be more performant and responsive for users. This guide includes a utility file for GraphQL queries.

    Your app can also get data from the extension APIs, which includes data on the current resource from the `data` API.

    To begin writing the block, you'll initially need to populate the block with the existing issue data. To achieve this, you'll use direct API to query the metafield. You'll use the metafield data to populate a paginated list in the block. Paginating the issues prevents the block from becoming too tall and difficult for users to interact with.

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/utils.js" />

      Create a new file at `./src/utils.js` and add the GraphQL queries that the extension uses to read and write data to the GraphQL Admin API.

      <Resources>
        [metafieldDefinitionCreate](/docs/api/admin-graphql/latest/mutations/metafieldDefinitionCreate)
        [metafieldsSet](/docs/api/admin-graphql/latest/mutations/metafieldsSet)
      </Resources>
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.connect-api-one"/>

      Import the `getIssues` utility method from the `utils.js` file. You'll use it to query the GraphQL Admin API for the initial data for the extension.
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.get-initial-data"/>

      ### Get initial data and set up pagination

      Use the `getIssues` utility method to fetch the initial data for the extension. Add a function to manage pagination.
    </Substep>

    <br />

    <Notice type="note" title="Tip">
      At this point, you can use the developer console to [run your app's server and preview your extension](#step-4-test-the-extension). After you preview the extension, changes to your extension's code automatically reload the extension that you're previewing. This enables you to preview your extension and see it update live as you make changes to the code.
    </Notice>
  </Step>

  <Step>
    ## Update data and integrate with the page's contextual save bar

    Next, you'll create a status dropdown and a delete button that enables users to either mark issues as completed or remove them entirely. When you create the status dropdown, you'll integrate it with the page's contextual save bar. This enables users to save changes to your block using the same controls that they would use to save changes to other fields in the Shopify admin.

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.connect-api-one"/>

      Import the `updateIssues` utility method and use it to update the extension state.
    </Substep>

    <Substep>
      <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/issue-tracker-block/src/BlockExtension.jsx" tag="build-admin-block.add-change-and-delete-handlers"/>

      ### Handle status changes and deleting issues

      Add the functions to handle deleting and changing the status.
      Call the `updateIssues` utility method when the issue is deleted and when the form is submitted.
    </Substep>

    <br />

    <Notice type="note" title="Tip">
      For more information on how to integrate with the contextual save bar, refer to this [reference](/docs/api/admin-extensions/latest#using-forms).
    </Notice>

  </Step>

  <Step>
    ## Test the extension

    After you've built the extension, test it with the following steps:

    1.  Navigate to your app directory:

        <Codeblock terminal>
          ```bash
          cd <directory>
          ```
        </Codeblock>

    2.  To build and preview your app, either start or restart your server with the following command:

        <Codeblock terminal>
          ```bash
          shopify app dev
          ```
        </Codeblock>

    3. Press `p` to open the developer console.

    4. In the developer console page, click on the preview link for the issue tracker block extension. The product details page opens. If you don't have a product in your store, then you need to create one.

    5. To find your block, scroll to the bottom of the page. It should display the issues that you've created so far.

    ![The developer console with the both new admin extension and the block extension in the list.](/assets/admin/admin-actions-and-block/build-an-admin-block/dev-console.png)

    6. When you change the status of an issue, the contextual save bar should display. The change is saved when you click the Save button.

    ![The new block extension at the bottom of the page. Issues that have been created with the action display.](/assets/admin/admin-actions-and-block/build-an-admin-block/block-on-page-csb.png)
  </Step>
</StepSection>

<NextSteps>
  ### Next steps

  <CardGrid>
    <LinkCard href="/docs/apps/admin/admin-actions-and-blocks/connect-action-and-block">
      #### Connect action and block extensions

      Complete the next section in this tutorial series by learning how to connect action and block extensions to enable issue editing.
    </LinkCard>

    <LinkCard href="/docs/apps/build/admin/actions-blocks/hide-extensions">
      #### Hide extensions

      Learn how to hide action extensions when they're not useful or relevant.
    </LinkCard>

    <LinkCard href="/docs/api/admin-extensions/extension-targets">
      #### Extension targets

      Learn about the surfaces in the Shopify admin where you can create admin extensions.
    </LinkCard>

    <LinkCard href="/docs/api/admin-extensions/components">
      #### Components

      Learn about the full set of available components for writing admin UI extensions.
    </LinkCard>

        <LinkCard href="/docs/apps/deployment/app-versions">
      #### Deploy

      Learn how to deploy your extension to merchants.
    </LinkCard>
  </CardGrid>
</NextSteps>