Command Palette

Search for a command to run...

Loading component...

Components paid UniSwap Country Dialog

UniSwap Country Dialog

A modern country selector dialog with real-time search functionality. Features a clean, modern UI with flag display, search capabilities, and seamless integration with React Query for efficient data fetching and caching.

Dependencies

Interaction Type

Click to open country selector
Search countries by name or code

CLI UNAVAILABLE

pro component, try copying the source code from top right corner

Manual setup

npx shadcn-ui@latest add dialog
npm i @tanstack/react-query lucide-react

Setup QueryClient

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

// Create a client
const queryClient = new QueryClient();

// Wrap your Layout
function Layout({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
}

How to use

import { CountrySelectDialog } from "@/components/v1/skiper20";

const Skiper20Demo = () => {
  const [isLayoutOpen, setIsLayoutOpen] = useState(false);
  const [selectedCountry, setSelectedCountry] = useState<Country | null>(null);

  const toggleLayout = () => {
    setIsLayoutOpen(!isLayoutOpen);
  };

  const handleSelectCountry = (country: Country) => {
    setSelectedCountry(country);
  };

  return (
    <div className="flex h-full w-screen items-center justify-center bg-[#131313] text-white">
      <button
        onClick={toggleLayout}
        className="flex items-center justify-center gap-1 rounded-full bg-[#2F2F2F] p-1.5 transition-colors duration-200 hover:bg-[#3A3A3A]"
      >
        {selectedCountry ? (
          <>
            <div className="size-6 overflow-hidden rounded-full">
              <img
                src={selectedCountry.flag}
                alt={selectedCountry.name}
                className="size-full object-cover"
              />
            </div>
          </>
        ) : (
          <>
            <div className="size-6 overflow-hidden rounded-full">
              <img
                src="https://flagcdn.com/us.svg"
                alt=""
                className="size-full object-cover"
              />
            </div>
          </>
        )}
        <ChevronDown className="size-5" />
      </button>

      <CountrySelectDialog
        isOpen={isLayoutOpen}
        onClose={() => setIsLayoutOpen(false)}
        onSelectCountry={handleSelectCountry}
        selectedCountry={selectedCountry}
      />
    </div>
  );
};
Props
Description

isOpen

Controls dialog open/close state

onClose

Callback when dialog should close

onSelectCountry

Callback when country is selected

selectedCountry

Currently selected country or null

React Query Customization

const {
  data: countries = [],
  isLoading,
  error,
  isError,
} = useQuery({
  queryKey: ["countries"],
  queryFn: fetchCountries,
  staleTime: 1000 * 60 * 5, // Data considered fresh for 5 minutes
  gcTime: 1000 * 60 * 10, // Keep in cache for 10 minutes
});

Optional: Server-Side Country Detection

In Next.js, the easiest and most reliable way is to get the country server-side from the IP address (or use built-in CDN headers if hosting on Vercel).

1. Using Vercel's built-in country heade

Vercel automatically provides x-vercel-ip-country in the request headers.

  • Works only if deployed on Vercel.
  • Doesn't require any external API.
//middleware.js
import { NextResponse } from "next/server";

export function middleware(req) {
  const country = req.headers.get("x-vercel-ip-country") || "Unknown";
  console.log("User country:", country);

  const res = NextResponse.next();
  res.headers.set("x-user-country", country); // pass to client if needed
  return res;
}

2. Using IP Geolocation API (works anywhere)

// pages/api/get-country.js

export default async function handler(req, res) {
  const ip =
    req.headers["x-forwarded-for"]?.split(",")[0] || req.socket.remoteAddress;
  const response = await fetch(`https://ipapi.co/${ip}/json/`);
  const data = await response.json();
  res.status(200).json({ country: data.country_name || "Unknown" });
}
// client side fetch

export default function Home() {
  const [country, setCountry] = React.useState("");

  React.useEffect(() => {
    fetch("/api/get-country")
      .then((res) => res.json())
      .then((data) => setCountry(data.country));
  }, []);

  return <div>User is from: {country}</div>;
}

Attribution

Inspired by and adapted from Uniswap

Source code

Click on the top right
to view the source code

Keep in mind

Most components here are recreations of the best out there. I don't claim to be the original creator. This is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone, but if I missed something, let me know.

Contact

Additionlly, if you find any bug or issue, feel free to
Drop a dm.

License & Usage:

  • Free to use and modify in both personal and commercial projects.
  • Attribution to Skiper UI is required when using the free version.
  • No attribution required with Skiper UI Pro.