Inputs

Country Prefix

A native country-code list on the left and the number on the right inside one border: the list is sized in ch, so the number never jumps.

  • inputgroup
  • phone
  • select
  • form

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/inputgroup-002?lang=en

Код страны и номер уходят двумя полями — склеит их сервер.

Show the full instructions

What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

# Install and place "inputgroup-002" (Country Prefix) from VibeUI

## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/inputgroup-002.json

Registry item: https://vibeui.ru/r/inputgroup-002.json
Installs to: components/vibeui/inputgroup-002.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.

Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.

## 2. What it is
A native country-code list on the left and the number on the right inside one border: the list is sized in ch, so the number never jumps.

A server-rendered country-code and number group: a native select on the left, the field on the right, one border and a ch-sized list. Zero dependencies, one file.

## 3. How to use it
import { Inputgroup002 } from "@/components/vibeui/inputgroup-002"

<Inputgroup002
  name="phone"
  label="Contact phone"
  countries={[{ code: "+44", title: "United Kingdom" }]}
/>

Read the installed file for the full prop list.

## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.

Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)

## 5. Keep exactly as installed
- the local --vibeui-inputgroup-002-* palette — do not swap it for your theme tokens
- the collapsed borders: neighbours carry a negative margin so the halves share one line instead of two
- raising the focused element with z-index — without it the neighbour's border clips half the ring
- the native select: keyboard support, type-ahead and the system wheel on phones come with it
- the ch width on the select: changing the code must not shift the number sideways
- submitting two separate form fields — joining code and number is the server's job, it knows the format

## 6. You may change
- the label copy and the countries array
- the name prop — both form field names are built from it
- the placeholder format for your country
- the accent through the accent prop

## 7. Rules
- There is no number mask here: it depends on the country and changes with the code.
- Do not fold the code into the field value: people will start deleting it with the number.
- Keep the country list short or make it searchable: thirty options in a select are painful.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.

## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.

For developers

npx shadcn@latest add https://vibeui.ru/r/inputgroup-002.json
https://vibeui.ru/r/inputgroup-002.json

Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-inputgroup-002-*. Серверный: состояния нет. Слева нативный <select> с appearance:none и стрелкой из двух градиентов, справа поле телефона. Ширина select задана в ch, чтобы смена кода не двигала номер. Рамка собрана схлопыванием границ, фокус поднимается z-index'ом. Код и номер уходят двумя полями формы: `${name}-code` и name.

Component source

The same file your agent installs. Here in case you would rather copy it by hand.

import type { ComponentPropsWithoutRef, CSSProperties } from "react"

export type Inputgroup002Country = {
  code: string
  title: string
}

export type Inputgroup002Props = Omit<
  ComponentPropsWithoutRef<"div">,
  "children"
> & {
  name?: string
  label?: string
  countries?: Inputgroup002Country[]
  hint?: string
  accent?: string
}

// Идея компонента: слева нативный select с кодом страны, справа номер, и обе
// половины делят одну рамку. Select именно нативный — от него бесплатно
// достаются клавиатура, поиск по букве и системное колесо на телефоне.
// Ширина select не резиновая: она задана в ch, чтобы номер не прыгал при
// смене страны. Код и номер уходят двумя полями формы — склеивать их должен
// сервер, он же знает формат.
const STYLES = `
:where([data-vibeui-block="inputgroup-002"]){
--vibeui-inputgroup-002-surface:oklch(1 0 0);
--vibeui-inputgroup-002-shell:oklch(0.91 0.006 265);
--vibeui-inputgroup-002-fg:oklch(0.23 0.014 265);
--vibeui-inputgroup-002-muted:oklch(0.55 0.014 265);
--vibeui-inputgroup-002-field:oklch(0.99 0.002 265);
--vibeui-inputgroup-002-fixed:oklch(0.965 0.003 265);
--vibeui-inputgroup-002-border:oklch(0.86 0.008 265);
--vibeui-inputgroup-002-accent:oklch(0.53 0.16 200);
--vibeui-inputgroup-002-radius:0.75rem;
--vibeui-inputgroup-002-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="inputgroup-002"]{
display:flex;flex-direction:column;gap:0.4375rem;
width:100%;max-width:22rem;box-sizing:border-box;padding:0.875rem;
background:var(--vibeui-inputgroup-002-surface);
border:1px solid var(--vibeui-inputgroup-002-shell);border-radius:0.875rem;
font-family:var(--vibeui-inputgroup-002-font);color:var(--vibeui-inputgroup-002-fg);
}
[data-vibeui-block="inputgroup-002"] *{box-sizing:border-box}
[data-vibeui-block="inputgroup-002"] label{font-size:0.8125rem;font-weight:600}
[data-vibeui-block="inputgroup-002"] [data-part="group"]{display:flex;align-items:stretch}
[data-vibeui-block="inputgroup-002"] [data-part="group"] > *{
position:relative;height:2.75rem;
border:1px solid var(--vibeui-inputgroup-002-border);
border-radius:0;margin-left:-1px;font:inherit;font-size:0.875rem;color:inherit;
}
[data-vibeui-block="inputgroup-002"] [data-part="group"] > *:first-child{
margin-left:0;
border-radius:var(--vibeui-inputgroup-002-radius) 0 0 var(--vibeui-inputgroup-002-radius);
}
[data-vibeui-block="inputgroup-002"] [data-part="group"] > *:last-child{
border-radius:0 var(--vibeui-inputgroup-002-radius) var(--vibeui-inputgroup-002-radius) 0;
}
[data-vibeui-block="inputgroup-002"] [data-part="group"] > *:focus{
z-index:1;outline:2px solid var(--vibeui-inputgroup-002-accent);outline-offset:-1px;
border-color:var(--vibeui-inputgroup-002-accent);
}
/* Ширина в ch: код страны меняется, а номер не должен ездить. */
[data-vibeui-block="inputgroup-002"] select{
appearance:none;flex:none;width:7.5ch;padding:0 1.375rem 0 0.75rem;cursor:pointer;
background:var(--vibeui-inputgroup-002-fixed);
font-variant-numeric:tabular-nums;font-weight:600;
background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);
background-position:calc(100% - 0.9rem) 50%,calc(100% - 0.6rem) 50%;
background-size:0.3rem 0.3rem,0.3rem 0.3rem;
background-repeat:no-repeat;
}
[data-vibeui-block="inputgroup-002"] input{
flex:1;min-width:0;padding:0 0.875rem;
background:var(--vibeui-inputgroup-002-field);
font-variant-numeric:tabular-nums;letter-spacing:0.02em;
}
[data-vibeui-block="inputgroup-002"] [data-part="hint"]{
margin:0;font-size:0.75rem;line-height:1.4;color:var(--vibeui-inputgroup-002-muted);
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="inputgroup-002"] *{animation:none!important;transition:none!important}}
`

const COUNTRIES: Inputgroup002Country[] = [
  { code: "+7", title: "Россия" },
  { code: "+375", title: "Беларусь" },
  { code: "+77", title: "Казахстан" },
  { code: "+995", title: "Грузия" },
]

/**
 * Сцепка «код страны + номер»: нативный select слева, номер справа, рамка одна.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Inputgroup002({
  name = "phone",
  label = "Телефон для связи",
  countries = COUNTRIES,
  hint = "Код страны и номер уходят двумя полями — склеит их сервер.",
  accent,
  className,
  style,
  ...props
}: Inputgroup002Props) {
  const palette = {
    ...(accent ? { "--vibeui-inputgroup-002-accent": accent } : null),
    ...style,
  } as CSSProperties

  return (
    <>
      <style href="vibeui-inputgroup-002" precedence="medium">
        {STYLES}
      </style>
      <div
        {...props}
        data-vibeui-block="inputgroup-002"
        className={className}
        style={palette}
      >
        <label htmlFor={`${name}-number`}>{label}</label>
        <div data-part="group">
          <select
            name={`${name}-code`}
            aria-label="Код страны"
            defaultValue={countries[0]?.code}
          >
            {countries.map((country) => (
              <option key={country.code} value={country.code}>
                {country.code}
              </option>
            ))}
          </select>
          <input
            id={`${name}-number`}
            name={name}
            type="tel"
            inputMode="tel"
            autoComplete="tel-national"
            placeholder="999 000-00-00"
            aria-describedby={`${name}-hint`}
          />
        </div>
        <p data-part="hint" id={`${name}-hint`}>
          {hint}
        </p>
      </div>
    </>
  )
}