All blocks

SEO Location Kit

Coordinate inputs with breadcrumb nav and SERP meta preview for property or locality pages.

Live preview

Location SEO kit
Breadcrumb navigation and suggested page meta for a WGS84 point.

Breadcrumb

No breadcrumb for this point.

Meta preview

No meta suggestions for this point.

Install

$bunx shadcn@latest add https://mapbase.dev/r/seo-location-kit.json

The shadcn CLI copies the file(s) below into your tree, installs npm dependencies, and recursively pulls registry dependencies (including from cross-registry URLs).

npm dependencies

mapbaselucide-react

Registry dependencies

cardinputlabelbuttonhttps://mapbase.dev/r/seo-breadcrumb-nav.jsonhttps://mapbase.dev/r/seo-meta-preview.json

Source

components/mapbase/seo-location-kit.tsx
"use client"

import * as React from "react"
import { type CountryCode } from "mapbase"

import { Button } from "@/components/ui/button"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { SeoBreadcrumbNav } from "@/components/mapbase/seo-breadcrumb-nav"
import { SeoMetaPreview } from "@/components/mapbase/seo-meta-preview"

export type SeoLocationKitProps = {
  apiKey: string
  baseUrl?: string
  initialLng?: number
  initialLat?: number
  country?: CountryCode
  siteBaseUrl?: string
  siteName?: string
  className?: string
}

const DEFAULT_LNG = -9.1393
const DEFAULT_LAT = 38.7223

/**
 * Property or locality page starter: coordinate inputs, visible breadcrumb,
 * and SERP-style meta preview from the Mapbase SEO API.
 */
export function SeoLocationKit({
  apiKey,
  baseUrl,
  initialLng = DEFAULT_LNG,
  initialLat = DEFAULT_LAT,
  country,
  siteBaseUrl = "https://example.com",
  siteName = "Acme Realty",
  className,
}: SeoLocationKitProps) {
  const [lngInput, setLngInput] = React.useState(String(initialLng))
  const [latInput, setLatInput] = React.useState(String(initialLat))
  const [lng, setLng] = React.useState(initialLng)
  const [lat, setLat] = React.useState(initialLat)

  const apply = () => {
    const nextLng = Number.parseFloat(lngInput)
    const nextLat = Number.parseFloat(latInput)
    if (!Number.isFinite(nextLng) || !Number.isFinite(nextLat)) return
    setLng(nextLng)
    setLat(nextLat)
  }

  return (
    <Card className={className}>
      <CardHeader>
        <CardTitle>Location SEO kit</CardTitle>
        <CardDescription>
          Breadcrumb navigation and suggested page meta for a WGS84 point.
        </CardDescription>
      </CardHeader>
      <CardContent className="flex flex-col gap-6">
        <div className="flex flex-wrap items-end gap-3">
          <div className="flex min-w-[8rem] flex-col gap-1.5">
            <Label htmlFor="seo-kit-lng" className="text-xs">
              Longitude
            </Label>
            <Input
              id="seo-kit-lng"
              inputMode="decimal"
              value={lngInput}
              onChange={(e) => setLngInput(e.target.value)}
              className="h-8 font-mono text-sm"
            />
          </div>
          <div className="flex min-w-[8rem] flex-col gap-1.5">
            <Label htmlFor="seo-kit-lat" className="text-xs">
              Latitude
            </Label>
            <Input
              id="seo-kit-lat"
              inputMode="decimal"
              value={latInput}
              onChange={(e) => setLatInput(e.target.value)}
              className="h-8 font-mono text-sm"
            />
          </div>
          <Button type="button" size="sm" className="h-8" onClick={apply}>
            Update
          </Button>
        </div>

        <div className="flex flex-col gap-2">
          <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
            Breadcrumb
          </p>
          <SeoBreadcrumbNav
            apiKey={apiKey}
            baseUrl={baseUrl}
            lng={lng}
            lat={lat}
            country={country}
            siteBaseUrl={siteBaseUrl}
          />
        </div>

        <div className="flex flex-col gap-2">
          <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
            Meta preview
          </p>
          <SeoMetaPreview
            apiKey={apiKey}
            baseUrl={baseUrl}
            lng={lng}
            lat={lat}
            country={country}
            siteBaseUrl={siteBaseUrl}
            siteName={siteName}
          />
        </div>
      </CardContent>
    </Card>
  )
}