Skip to content
Back to skills

076 Building 8264fa2d

ASecurity

Guide for building UI extensions and Shopify Functions.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentjavascriptjavabashreacttestingapibackendsecurityperformance

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 076-building_8264fa2d --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 076 Building 8264fa2d?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 076 Building 8264fa2d
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-076-building-8264fa2d/badge)](https://www.skillsdirectory.com/skills/tools-only-076-building-8264fa2d)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Extensions Reference

Guide for building UI extensions and Shopify Functions.

## Checkout UI Extensions

Customize checkout and thank-you pages with native-rendered components.

### Extension Points

**Block Targets (Merchant-Configurable):**
- `purchase.checkout.block.render` - Main checkout
- `purchase.thank-you.block.render` - Thank you page

**Static Targets (Fixed Position):**
- `purchase.checkout.header.render-after`
- `purchase.checkout.contact.render-before`
- `purchase.checkout.shipping-option-list.render-after`
- `purchase.checkout.payment-method-list.render-after`
- `purchase.checkout.footer.render-before`

### Setup

```bash
shopify app generate extension --type checkout_ui_extension
```

Configuration (`shopify.extension.toml`):
```toml
api_version = "2025-01"
name = "gift-message"
type = "ui_extension"

[[extensions.targeting]]
target = "purchase.checkout.block.render"

[capabilities]
network_access = true
api_access = true
```

### Basic Example

```javascript
import { reactExtension, BlockStack, TextField, Checkbox, useApi } from '@shopify/ui-extensions-react/checkout';

export default reactExtension('purchase.checkout.block.render', () => <Extension />);

function Extension() {
  const [message, setMessage] = useState('');
  const [isGift, setIsGift] = useState(false);
  const { applyAttributeChange } = useApi();

  useEffect(() => {
    if (isGift) {
      applyAttributeChange({
        type: 'updateAttribute',
        key: 'gift_message',
        value: message
      });
    }
  }, [message, isGift]);

  return (
    <BlockStack spacing="loose">
      <Checkbox checked={isGift} onChange={setIsGift}>
        This is a gift
      </Checkbox>
      {isGift && (
        <TextField
          label="Gift Message"
          value={message}
          onChange={setMessage}
          multiline={3}
        />
      )}
    </BlockStack>
  );
}
```

### Common Hooks

**useApi:**
```javascript
const { extensionPoint, shop, storefront, i18n, sessionToken } = useApi();
```

**useCartLines:**
```javascript
const lines = useCartLines();
lines.forEach(line => {
  console.log(line.merchandise.product.title, line.quantity);
});
```

**useShippingAddress:**
```javascript
const address = useShippingAddress();
console.log(address.city, address.countryCode);
```

**useApplyCartLinesChange:**
```javascript
const applyChange = useApplyCartLinesChange();

async function addItem() {
  await applyChange({
    type: 'addCartLine',
    merchandiseId: 'gid://shopify/ProductVariant/123',
    quantity: 1
  });
}
```

### Core Components

**Layout:**
- `BlockStack` - Vertical stacking
- `InlineStack` - Horizontal layout
- `Grid`, `GridItem` - Grid layout
- `View` - Container
- `Divider` - Separator

**Input:**
- `TextField` - Text input
- `Checkbox` - Boolean
- `Select` - Dropdown
- `DatePicker` - Date selection
- `Form` - Form wrapper

**Display:**
- `Text`, `Heading` - Typography
- `Banner` - Messages
- `Badge` - Status
- `Image` - Images
- `Link` - Hyperlinks
- `List`, `ListItem` - Lists

**Interactive:**
- `Button` - Actions
- `Modal` - Overlays
- `Pressable` - Click areas

## Admin UI Extensions

Extend Shopify admin interface.

### Admin Action

Custom actions on resource pages.

```bash
shopify app generate extension --type admin_action
```

```javascript
import { reactExtension, AdminAction, Button } from '@shopify/ui-extensions-react/admin';

export default reactExtension('admin.product-details.action.render', () => <Extension />);

function Extension() {
  const { data } = useData();

  async function handleExport() {
    const response = await fetch('/api/export', {
      method: 'POST',
      body: JSON.stringify({ productId: data.product.id })
    });
    console.log('Exported:', await response.json());
  }

  return (
    <AdminAction
      title="Export Product"
      primaryAction={<Button onPress={handleExport}>Export</Button>}
    />
  );
}
```

**Targets:**
- `admin.product-details.action.render`
- `admin.order-details.action.render`
- `admin.customer-details.action.render`

### Admin Block

Embedded content in admin pages.

```javascript
import { reactExtension, BlockStack, Text, Badge } from '@shopify/ui-extensions-react/admin';

export default reactExtension('admin.product-details.block.render', () => <Extension />);

function Extension() {
  const { data } = useData();
  const [analytics, setAnalytics] = useState(null);

  useEffect(() => {
    fetchAnalytics(data.product.id).then(setAnalytics);
  }, []);

  return (
    <BlockStack>
      <Text variant="headingMd">Product Analytics</Text>
      <Text>Views: {analytics?.views || 0}</Text>
      <Text>Conversions: {analytics?.conversions || 0}</Text>
      <Badge tone={analytics?.trending ? "success" : "info"}>
        {analytics?.trending ? "Trending" : "Normal"}
      </Badge>
    </BlockStack>
  );
}
```

**Targets:**
- `admin.product-details.block.render`
- `admin.order-details.block.render`
- `admin.customer-details.block.render`

## POS UI Extensions

Customize Point of Sale experience.

### Smart Grid Tile

Quick access action on POS home screen.

```javascript
import { reactExtension, SmartGridTile } from '@shopify/ui-extensions-react/pos';

export default reactExtension('pos.home.tile.render', () => <Extension />);

function Extension() {
  function handlePress() {
    // Navigate to custom workflow
  }

  return (
    <SmartGridTile
      title="Gift Cards"
      subtitle="Manage gift cards"
      onPress={handlePress}
    />
  );
}
```

### POS Modal

Full-screen workflow.

```javascript
import { reactExtension, Screen, BlockStack, Button, TextField } from '@shopify/ui-extensions-react/pos';

export default reactExtension('pos.home.modal.render', () => <Extension />);

function Extension() {
  const { navigation } = useApi();
  const [amount, setAmount] = useState('');

  function handleIssue() {
    // Issue gift card
    navigation.pop();
  }

  return (
    <Screen name="Gift Card" title="Issue Gift Card">
      <BlockStack>
        <TextField label="Amount" value={amount} onChange={setAmount} />
        <TextField label="Recipient Email" />
        <Button onPress={handleIssue}>Issue</Button>
      </BlockStack>
    </Screen>
  );
}
```

## Customer Account Extensions

Customize customer account pages.

### Order Status Extension

```javascript
import { reactExtension, BlockStack, Text, Button } from '@shopify/ui-extensions-react/customer-account';

export default reactExtension('customer-account.order-status.block.render', () => <Extension />);

function Extension() {
  const { order } = useApi();

  function handleReturn() {
    // Initiate return
  }

  return (
    <BlockStack>
      <Text variant="headingMd">Need to return?</Text>
      <Text>Start return for order {order.name}</Text>
      <Button onPress={handleReturn}>Start Return</Button>
    </BlockStack>
  );
}
```

**Targets:**
- `customer-account.order-status.block.render`
- `customer-account.order-index.block.render`
- `customer-account.profile.block.render`

## Shopify Functions

Serverless backend customization.

### Function Types

**Discounts:**
- `order_discount` - Order-level discounts
- `product_discount` - Product-specific discounts
- `shipping_discount` - Shipping discounts

**Payment Customization:**
- Hide/rename/reorder payment methods

**Delivery Customization:**
- Custom shipping options
- Delivery rules

**Validation:**
- Cart validation rules
- Checkout validation

### Create Function

```bash
shopify app generate extension --type function
```

### Order Discount Function

```javascript
// input.graphql
query Input {
  cart {
    lines {
      quantity
      merchandise {
        ... on ProductVariant {
          product {
            hasTag(tag: "bulk-discount")
          }
        }
      }
    }
  }
}

// function.js
export default function orderDiscount(input) {
  const targets = input.cart.lines
    .filter(line => line.merchandise.product.hasTag)
    .map(line => ({
      productVariant: { id: line.merchandise.id }
    }));

  if (targets.length === 0) {
    return { discounts: [] };
  }

  return {
    discounts: [{
      targets,
      value: {
        percentage: {
          value: 10  // 10% discount
        }
      }
    }]
  };
}
```

### Payment Customization Function

```javascript
export default function paymentCustomization(input) {
  const hidePaymentMethods = input.cart.lines.some(
    line => line.merchandise.product.hasTag
  );

  if (!hidePaymentMethods) {
    return { operations: [] };
  }

  return {
    operations: [{
      hide: {
        paymentMethodId: "gid://shopify/PaymentMethod/123"
      }
    }]
  };
}
```

### Validation Function

```javascript
export default function cartValidation(input) {
  const errors = [];

  // Max 5 items per cart
  if (input.cart.lines.length > 5) {
    errors.push({
      localizedMessage: "Maximum 5 items allowed per order",
      target: "cart"
    });
  }

  // Min $50 for wholesale
  const isWholesale = input.cart.lines.some(
    line => line.merchandise.product.hasTag
  );

  if (isWholesale && input.cart.cost.totalAmount.amount < 50) {
    errors.push({
      localizedMessage: "Wholesale orders require $50 minimum",
      target: "cart"
    });
  }

  return { errors };
}
```

## Network Requests

Extensions can call external APIs.

```javascript
import { useApi } from '@shopify/ui-extensions-react/checkout';

function Extension() {
  const { sessionToken } = useApi();

  async function fetchData() {
    const token = await sessionToken.get();

    const response = await fetch('https://your-app.com/api/data', {
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    });

    return await response.json();
  }
}
```

## Best Practices

**Performance:**
- Lazy load data
- Memoize expensive computations
- Use loading states
- Minimize re-renders

**UX:**
- Provide clear error messages
- Show loading indicators
- Validate inputs
- Support keyboard navigation

**Security:**
- Verify session tokens on backend
- Sanitize user input
- Use HTTPS for all requests
- Don't expose sensitive data

**Testing:**
- Test on development stores
- Verify mobile/desktop
- Check accessibility
- Test edge cases

## Resources

- Checkout Extensions: https://shopify.dev/docs/api/checkout-extensions
- Admin Extensions: https://shopify.dev/docs/apps/admin/extensions
- Functions: https://shopify.dev/docs/apps/functions
- Components: https://shopify.dev/docs/api/checkout-ui-extensions/components

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.