BigBlocks

Create Listing

List an ordinal NFT for sale on the global BSV orderbook with a dialog-based price and payout address form

Primary Variant

Ghost Variant

A dialog-triggered block for listing ordinal NFTs. A button opens a dialog showing an ordinal preview, price input (satoshis), payout address, and a confirm action. Validates price bounds and address before enabling submission. The underlying useCreateListing hook is also exported for headless usage.

Installation

bunx shadcn@latest add https://registry.bigblocks.dev/r/create-listing.json

Usage

import { CreateListing, type ListOrdinalParams, type ListOrdinalResult } from "@/components/blocks/create-listing"
 
export default function OrdinalDetailPage() {
  const ordinal = {
    outpoint: "abc123...def.0",
    name: "Rare Pepe #42",
    contentType: "image/png",
    origin: "abc123...def.0",
  }
 
  const handleList = async (params: ListOrdinalParams): Promise<ListOrdinalResult> => {
    try {
      const result = await listOrdinal.execute(ctx, {
        ordinal: walletOutput,
        price: params.price,
        payAddress: params.payAddress,
      })
      return { txid: result.txid }
    } catch (err) {
      return { error: err instanceof Error ? err.message : "Listing failed" }
    }
  }
 
  return (
    <CreateListing
      ordinal={ordinal}
      onList={handleList}
      onListed={(result) => console.log("Listed:", result.txid)}
      defaultPayAddress="1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
      triggerLabel="List for Sale"
    />
  )
}

Variants

The trigger button accepts variant from class-variance-authority. Pass the variant name as a prop.

<CreateListing ordinal={ordinal} onList={handleList} variant="outline" />
<CreateListing ordinal={ordinal} onList={handleList} variant="ghost" />

API Reference

CreateListing

PropTypeDefaultDescription
ordinalOrdinalItem—Required. The ordinal to list for sale.
onList(params: ListOrdinalParams) => Promise<ListOrdinalResult>—Required. Executes the on-chain listing action.
onListed(result: ListOrdinalResult) => void—Called after a successful listing.
onError(error: Error) => void—Called when the listing fails.
defaultPayAddressstring""Pre-fills the payout address field.
triggerLabelstring"List for Sale"Text label on the trigger button.
variantVariantProps<typeof createListingTriggerVariants>"default"Visual style of the trigger button.
classNamestring—Additional CSS classes applied to the trigger.

OrdinalItem

interface OrdinalItem {
  outpoint: string      // txid.vout format
  name?: string         // Display name
  contentType?: string  // MIME type
  origin?: string       // Origin outpoint for collection grouping
}

ListOrdinalParams

interface ListOrdinalParams {
  ordinal: OrdinalItem  // The ordinal being listed
  price: number         // Price in satoshis
  payAddress: string    // Address that receives payment on purchase
}

ListOrdinalResult

interface ListOrdinalResult {
  txid?: string   // Transaction ID on success
  rawtx?: string  // Raw transaction hex (optional)
  error?: string  // Error message when listing failed
}

Hook

Use useCreateListing directly when you need a custom UI or want to embed the logic elsewhere.

import { useCreateListing } from "@/components/blocks/create-listing"
 
function CustomListingFlow({ ordinal, onList }) {
  const listing = useCreateListing({ ordinal, onList, defaultPayAddress: myAddress })
 
  return (
    <div>
      <input
        value={listing.priceInput}
        onChange={(e) => listing.setPriceInput(e.target.value)}
        placeholder="Price in satoshis"
      />
      {listing.validationError && <p>{listing.validationError}</p>}
      <button
        onClick={listing.handleList}
        disabled={!listing.canSubmit || listing.isListing}
      >
        List for {listing.priceSats.toLocaleString()} sats
      </button>
    </div>
  )
}

UseCreateListingReturn

PropertyTypeDescription
openbooleanWhether the dialog is open.
handleOpenChange(nextOpen: boolean) => voidOpen/close the dialog. Resets form on close.
priceInputstringCurrent raw price input string.
setPriceInput(value: string) => voidUpdate the price input.
payAddressstringCurrent payout address value.
setPayAddress(value: string) => voidUpdate the payout address.
isListingbooleanWhether a listing transaction is in progress.
resultListOrdinalResult | nullResult from the most recent listing attempt.
errorstring | nullError message from the most recent attempt.
priceSatsnumberParsed price in satoshis (0 if input is invalid).
validationErrorstring | nullHuman-readable validation error or null.
canSubmitbooleanWhether the form passes validation and can be submitted.
handleList() => Promise<void>Execute the listing. No-op if canSubmit is false.