# Account settings 01

> Comprehensive account settings interface with five separated sections: PersonalInfo with image upload (1MB limit validation, preview URL generation), country selector with flag icons; EmailPass for email and password changes; ConnectAccount for third-party app integrations; SocialUrl for social media profile links; and DangerZone with account deletion controls

A shadcn/ui block from the [@shadcn-studio](https://shadcnstudio.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-studio/account-settings-01).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-studio/account-settings-01
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-studio/account-settings-01-light-db8706ad53a87770.png
- Registry item: https://shadcnstudio.com/r/new-york-v4/account-settings-01.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnstudio.com/r/new-york-v4/account-settings-01.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `separator`, `tabs`, `utils`, `tooltip`, `checkbox`, `button`, `switch`, `label`, `card`, `select`, `dialog`, `input`, `input-group`, `toggle-group`, `table`

## Files

### `src/registry/new-york/blocks/dashboard-and-application/account-settings/account-settings-01/page.tsx`

```tsx
import { Tabs, TabsList, TabsTrigger } from '@/registry/new-york/ui/tabs'
import UserGeneral from '@/registry/new-york/components/blocks/account-settings-01/account-settings-01'

const tabs = [
  { name: 'General', value: 'general' },
  { name: 'Preferences', value: 'preferences' },
  { name: 'Users', value: 'users' }
]

const TabsUnderlineDemo = () => {
  return (
    <div className='w-full py-8'>
      <div className='mx-auto min-h-screen max-w-7xl px-4 sm:px-6 lg:px-8'>
        <Tabs defaultValue='general' className='gap-4'>
          <TabsList className='h-fit! w-full rounded-none border-b bg-transparent p-0 sm:justify-start'>
            {tabs.map(tab => (
              <TabsTrigger
                key={tab.value}
                value={tab.value}
                className='data-[state=active]:border-primary dark:data-[state=active]:border-primary rounded-none border-0 border-b-2 border-transparent data-[state=active]:shadow-none! sm:flex-0 dark:data-[state=active]:bg-transparent'
              >
                {tab.name}
              </TabsTrigger>
            ))}
          </TabsList>
        </Tabs>
        <div className='mt-4'>
          <UserGeneral />
        </div>
      </div>
    </div>
  )
}

export default TabsUnderlineDemo
```

### `src/registry/new-york/components/blocks/account-settings-01/account-settings-01.tsx`

```tsx
import { Separator } from '@/registry/new-york/ui/separator'

import PersonalInfo from '@/registry/new-york/components/blocks/account-settings-01/content/personal-info'
import EmailPass from '@/registry/new-york/components/blocks/account-settings-01/content/email-password'
import ConnectAccount from '@/registry/new-york/components/blocks/account-settings-01/content/connect-account'
import SocialUrl from '@/registry/new-york/components/blocks/account-settings-01/content/social-url'
import DangerZone from '@/registry/new-york/components/blocks/account-settings-01/content/danger-zone'

const UserGeneral = () => {
  return (
    <section className='py-3'>
      <div className='mx-auto max-w-7xl'>
        <PersonalInfo />
        <Separator className='my-10' />
        <EmailPass />
        <Separator className='my-10' />
        <ConnectAccount />
        <Separator className='my-10' />
        <SocialUrl />
        <Separator className='my-10' />
        <DangerZone />
      </div>
    </section>
  )
}

export default UserGeneral
```

### `src/registry/new-york/components/blocks/account-settings-01/content/connect-account.tsx`

```tsx
'use client'

import { useState } from 'react'

import { XIcon, PlusIcon } from 'lucide-react'

import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
  DialogTrigger
} from '@/registry/new-york/ui/dialog'
import { Button } from '@/registry/new-york/ui/button'
import { Input } from '@/registry/new-york/ui/input'
import { Label } from '@/registry/new-york/ui/label'

interface ConnectedAccount {
  id: string
  name: string
  iconUrl: string
}

const initialAccounts: ConnectedAccount[] = [
  {
    id: 'google',
    name: 'Google',
    iconUrl: 'https://cdn.shadcnstudio.com/ss-assets/brand-logo/google-icon.png'
  },
  {
    id: 'slack',
    name: 'Slack',
    iconUrl: 'https://cdn.shadcnstudio.com/ss-assets/brand-logo/slack-icon.png'
  }
]

const ConnectedAccount = () => {
  const [connectedAccounts, setConnectedAccounts] = useState<ConnectedAccount[]>(initialAccounts)
  const [isDialogOpen, setIsDialogOpen] = useState(false)

  const [appName, setAppName] = useState('')
  const [appUrl, setAppUrl] = useState('')
  const [appIconUrl, setAppIconUrl] = useState('')
  const [description, setDescription] = useState('')

  const handleRemoveAccount = (accountId: string) => {
    setConnectedAccounts(prev => prev.filter(account => account.id !== accountId))
  }

  const resetForm = () => {
    setAppName('')
    setAppUrl('')
    setAppIconUrl('')
    setDescription('')
  }

  const handleConnect = () => {
    if (!appName.trim() || !appUrl.trim()) return

    const id = appName.toLowerCase().replace(/\s+/g, '-')

    setConnectedAccounts(prev => [
      ...prev,
      {
        id,
        name: appName,
        iconUrl: appIconUrl.trim() || ''
      }
    ])

    resetForm()
    setIsDialogOpen(false)
  }

  return (
    <div className='grid grid-cols-1 gap-10 lg:grid-cols-3'>
      {/* Vertical Tabs List */}
      <div className='flex flex-col'>
        <h3 className='text-foreground font-semibold'>Connect Accounts</h3>
        <p className='text-muted-foreground text-sm'>Manage your connected accounts.</p>
      </div>

      {/* Content */}
      <div className='space-y-4 lg:col-span-2'>
        <div className='flex flex-wrap items-center gap-4'>
          {connectedAccounts.map(account => (
            <div key={account.id} className='flex w-fit items-center gap-3 rounded-md border p-2'>
              {account.iconUrl ? (
                <img src={account.iconUrl} alt={account.name} className='size-4 rounded' />
              ) : (
                <div className='bg-muted-foreground/10 text-muted-foreground flex size-4 items-center justify-center rounded text-sm font-medium'>
                  {account.name.charAt(0)}
                </div>
              )}

              <p className='text-sm font-medium'>{account.name}</p>
              <Button
                size='xs'
                variant='ghost'
                className='text-primary bg-primary/10 rounded-md transition-colors focus:ring-2 focus:ring-offset-2 focus:outline-none'
                aria-label={`Remove ${account.name}`}
                onClick={() => handleRemoveAccount(account.id)}
              >
                <XIcon className='size-3' aria-hidden='true' />
              </Button>
            </div>
          ))}

          {/* Add App Button + Modal */}
          <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
            <DialogTrigger asChild>
              <Button variant='outline' className='h-10.5' onClick={() => setIsDialogOpen(true)}>
                <PlusIcon className='size-4' />
                Add App
              </Button>
            </DialogTrigger>

            <DialogContent>
              <DialogHeader>
                <DialogTitle>Connect New App</DialogTitle>
                <DialogDescription>Add a new integration by providing the details below.</DialogDescription>
              </DialogHeader>

              <div className='grid gap-3 py-2'>
                <div className='grid gap-1'>
                  <Label>App Name</Label>
                  <Input value={appName} onChange={e => setAppName(e.target.value)} placeholder='e.g., Zoom' />
                </div>

                <div className='grid gap-1'>
                  <Label>App URL or Integration Key</Label>
                  <Input
                    value={appUrl}
                    onChange={e => setAppUrl(e.target.value)}
                    placeholder='https://app.example.com or key_abc123'
                  />
                </div>

                <div className='grid gap-1'>
                  <Label>Optional Description</Label>
                  <Input
                    value={description}
                    onChange={e => setDescription(e.target.value)}
                    placeholder='Notes about this integration (optional)'
                  />
                </div>
              </div>

              <DialogFooter>
                <Button
                  variant='outline'
                  onClick={() => {
                    resetForm()
                    setIsDialogOpen(false)
                  }}
                >
                  Cancel
                </Button>
                <Button onClick={handleConnect} disabled={!appName.trim() || !appUrl.trim()}>
                  Connect
                </Button>
              </DialogFooter>
            </DialogContent>
          </Dialog>
        </div>
        <p className='text-muted-foreground text-sm'>
          Connected accounts allow you to integrate with third-party services for enhanced functionality.
        </p>
      </div>
    </div>
  )
}

export default ConnectedAccount
```

### `src/registry/new-york/components/blocks/account-settings-01/content/danger-zone.tsx`

```tsx
import { Trash2Icon } from 'lucide-react'

import { Card, CardContent } from '@/registry/new-york/ui/card'
import { Button } from '@/registry/new-york/ui/button'
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogClose
} from '@/registry/new-york/ui/dialog'

const DangerZone = () => {
  return (
    <div className='grid grid-cols-1 gap-10 lg:grid-cols-3'>
      {/* Vertical Tabs List */}
      <div className='flex flex-col space-y-1'>
        <h3 className='font-semibold'>Danger Zone</h3>
        <p className='text-muted-foreground text-sm'>
          Delete your account permanently. This action will remove all your data and cannot be undone{' '}
          <a href='#' className='text-card-foreground font-medium hover:underline'>
            Learn more
          </a>
        </p>
      </div>

      {/* Content */}
      <div className='space-y-6 lg:col-span-2'>
        <Card>
          <CardContent>
            <div className='flex justify-between gap-4 max-lg:flex-col lg:items-center'>
              <div className='space-y-1'>
                <h3 className='text-sm font-medium'>Delete account</h3>
                <p className='text-muted-foreground text-sm'>
                  Delete your account permanently. This action will remove all your data and cannot be undone.
                </p>
              </div>
              <Dialog>
                <DialogTrigger asChild>
                  <Button
                    variant='outline'
                    className='hover:bg-destructive/10! text-destructive! border-destructive! focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 max-lg:w-full'
                  >
                    <Trash2Icon />
                    Delete
                  </Button>
                </DialogTrigger>
                <DialogContent className='sm:max-w-md'>
                  <DialogHeader className='space-y-2'>
                    <DialogTitle>Delete account</DialogTitle>
                    <div className='text-muted-foreground text-sm'>
                      Delete your account permanently. This action will remove all your data and cannot be undone.
                    </div>
                  </DialogHeader>
                  <DialogFooter className='mt-4 gap-4 sm:justify-end'>
                    <DialogClose asChild>
                      <Button variant='outline'>Cancel</Button>
                    </DialogClose>
                    <DialogClose asChild>
                      <Button variant='destructive'>Delete</Button>
                    </DialogClose>
                  </DialogFooter>
                </DialogContent>
              </Dialog>
            </div>
          </CardContent>
        </Card>
      </div>
    </div>
  )
}

export default DangerZone
```

### `src/registry/new-york/components/blocks/account-settings-01/content/email-password.tsx`

```tsx
'use client'

import { useMemo, useState } from 'react'

import { CheckIcon, MailIcon, XIcon, EyeIcon, EyeOffIcon } from 'lucide-react'

import { Button } from '@/registry/new-york/ui/button'
import { InputGroup, InputGroupAddon, InputGroupInput } from '@/registry/new-york/ui/input-group'
import { Label } from '@/registry/new-york/ui/label'

import { cn } from '@/registry/new-york/lib/utils'

const requirements = [
  { regex: /.{12,}/, text: 'At least 12 characters' },
  { regex: /[a-z]/, text: 'At least 1 lowercase letter' },
  { regex: /[A-Z]/, text: 'At least 1 uppercase letter' },
  { regex: /[0-9]/, text: 'At least 1 number' },
  {
    regex: /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>/?]/,
    text: 'At least 1 special character'
  }
]

const EmailPass = () => {
  const [isVisible, setIsVisible] = useState(false)

  const [password, setPassword] = useState('')

  const toggleVisibility = () => setIsVisible(prevState => !prevState)

  const strength = requirements.map(req => ({
    met: req.regex.test(password),
    text: req.text
  }))

  const strengthScore = useMemo(() => {
    return strength.filter(req => req.met).length
  }, [strength])

  const getColor = (score: number) => {
    if (score === 0) return 'bg-border'
    if (score <= 1) return 'bg-destructive'
    if (score <= 2) return 'bg-orange-500 '
    if (score <= 3) return 'bg-amber-500'
    if (score === 4) return 'bg-yellow-400'

    return 'bg-green-500'
  }

  const getText = (score: number) => {
    if (score === 0) return 'Enter a password'
    if (score <= 2) return 'Weak password'
    if (score <= 3) return 'Medium password'
    if (score === 4) return 'Strong password'

    return 'Very strong password'
  }

  return (
    <div className='grid grid-cols-1 gap-10 lg:grid-cols-3'>
      {/* Vertical Tabs List */}
      <div className='flex flex-col space-y-1'>
        <h3 className='font-semibold'>Email & Password</h3>
        <p className='text-muted-foreground text-sm'>Manage your email and password settings.</p>
      </div>

      {/* Content */}
      <div className='lg:col-span-2'>
        <form className='mx-auto space-y-6'>
          <div className='w-full space-y-2'>
            <Label htmlFor='email' className='gap-1'>
              Email<span className='text-destructive'>*</span>
            </Label>
            <InputGroup>
              <InputGroupInput id='email' type='email' placeholder='Email address' required />
              <InputGroupAddon align='inline-end' className='pr-2.75'>
                <MailIcon className='size-4' />
                <span className='sr-only'>Email</span>
              </InputGroupAddon>
            </InputGroup>
          </div>
          <div className='w-full space-y-2'>
            <Label htmlFor='current-password' className='gap-1'>
              Current Password<span className='text-destructive'>*</span>
            </Label>
            <InputGroup>
              <InputGroupInput
                id='current-password'
                type={isVisible ? 'text' : 'password'}
                placeholder='Password'
                required
              />
              <InputGroupAddon align='inline-end' className='pr-1.5'>
                <Button
                  variant='ghost'
                  size='icon'
                  onClick={() => setIsVisible(prevState => !prevState)}
                  className='text-muted-foreground focus-visible:ring-ring/50 rounded-l-none hover:bg-transparent'
                >
                  {isVisible ? <EyeOffIcon /> : <EyeIcon />}
                  <span className='sr-only'>{isVisible ? 'Hide password' : 'Show password'}</span>
                </Button>
              </InputGroupAddon>
            </InputGroup>
          </div>
          <div className='w-full space-y-2'>
            <Label htmlFor='new-password' className='gap-1'>
              New Password
              <span className='text-destructive'>*</span>
            </Label>
            <InputGroup className='mb-3'>
              <InputGroupInput
                id='new-password'
                type={isVisible ? 'text' : 'password'}
                placeholder='Password'
                value={password}
                onChange={e => setPassword(e.target.value)}
                required
              />
              <InputGroupAddon align='inline-end' className='pr-1.5'>
                <Button
                  variant='ghost'
                  size='icon'
                  onClick={toggleVisibility}
                  className='text-muted-foreground focus-visible:ring-ring/50 rounded-l-none hover:bg-transparent'
                >
                  {isVisible ? <EyeOffIcon /> : <EyeIcon />}
                  <span className='sr-only'>{isVisible ? 'Hide password' : 'Show password'}</span>
                </Button>
              </InputGroupAddon>
            </InputGroup>

            <div className='mb-4 flex h-1 w-full gap-1'>
              {Array.from({ length: 5 }).map((_, index) => (
                <span
                  key={index}
                  className={cn(
                    'h-full flex-1 rounded-full transition-all duration-500 ease-out',
                    index < strengthScore ? getColor(strengthScore) : 'bg-border'
                  )}
                />
              ))}
            </div>

            <p className='text-foreground text-sm font-medium'>{getText(strengthScore)}. Must contain :</p>

            <ul className='mb-4 space-y-1.5'>
              {strength.map((req, index) => (
                <li key={index} className='flex items-center gap-2'>
                  {req.met ? (
                    <CheckIcon className='size-4 text-green-600 dark:text-green-400' />
                  ) : (
                    <XIcon className='text-muted-foreground size-4' />
                  )}
                  <span
                    className={cn('text-xs', req.met ? 'text-green-600 dark:text-green-400' : 'text-muted-foreground')}
                  >
                    {req.text}
                    <span className='sr-only'>{req.met ? ' - Requirement met' : ' - Requirement not met'}</span>
                  </span>
                </li>
              ))}
            </ul>
          </div>

          <div className='mt-6 flex justify-end'>
            <Button type='submit' className='max-sm:w-full'>
              Save Changes
            </Button>
          </div>
        </form>
      </div>
    </div>
  )
}

export default EmailPass
```

### `src/registry/new-york/components/blocks/account-settings-01/content/personal-info.tsx`

```tsx
'use client'

import { useEffect, useRef, useState } from 'react'

import { UploadCloudIcon, TrashIcon, ImageIcon } from 'lucide-react'

import { Button } from '@/registry/new-york/ui/button'
import { Input } from '@/registry/new-york/ui/input'
import { Label } from '@/registry/new-york/ui/label'
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue
} from '@/registry/new-york/ui/select'

const countries = [
  { value: 'india', label: 'India', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/india.png' },
  { value: 'china', label: 'China', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/china.png' },
  { value: 'monaco', label: 'Monaco', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/monaco.png' },
  { value: 'serbia', label: 'Serbia', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/serbia.png' },
  { value: 'romania', label: 'Romania', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/romania.png' },
  { value: 'mayotte', label: 'Mayotte', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/mayotte.png' },
  { value: 'iraq', label: 'Iraq', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/iraq.png' },
  { value: 'syria', label: 'Syria', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/syria.png' },
  { value: 'korea', label: 'Korea', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/korea.png' },
  { value: 'zimbabwe', label: 'Zimbabwe', flag: 'https://cdn.shadcnstudio.com/ss-assets/flags/zimbabwe.png' }
]

const PersonalInfo = () => {
  const inputRef = useRef<HTMLInputElement | null>(null)
  const [file, setFile] = useState<File | null>(null)
  const [preview, setPreview] = useState<string | null>(null)

  useEffect(() => {
    if (!file) {
      const t = window.setTimeout(() => setPreview(null), 0)

      return () => clearTimeout(t)
    }

    const url = URL.createObjectURL(file)

    const t = window.setTimeout(() => setPreview(url), 0)

    return () => {
      clearTimeout(t)
      URL.revokeObjectURL(url)
    }
  }, [file])

  const onSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const f = e.target.files?.[0]

    if (!f) return

    if (!f.type.startsWith('image/')) {
      window.alert('Please select an image file')
      e.currentTarget.value = ''

      return
    }

    if (f.size > 1024 * 1024) {
      window.alert('File must be smaller than 1MB')
      e.currentTarget.value = ''

      return
    }

    setFile(f)
  }

  const openPicker = () => inputRef.current?.click()

  const remove = () => {
    setFile(null)
    if (inputRef.current) inputRef.current.value = ''
  }

  return (
    <div className='grid grid-cols-1 gap-10 lg:grid-cols-3'>
      {/* Vertical Tabs List */}
      <div className='flex flex-col space-y-1'>
        <h3 className='font-semibold'>Personal Information</h3>
        <p className='text-muted-foreground text-sm'>Manage your personal information and role.</p>
      </div>

      {/* Content */}
      <div className='space-y-6 lg:col-span-2'>
        <form className='mx-auto'>
          <div className='mb-6 w-full space-y-2'>
            <Label>Your Avatar</Label>
            <div className='flex items-center gap-4'>
              <div
                role='button'
                tabIndex={0}
                aria-label='Upload your avatar'
                onClick={openPicker}
                onKeyDown={e => {
                  if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault()
                    openPicker()
                  }
                }}
                className='flex h-20 w-20 cursor-pointer items-center justify-center overflow-hidden rounded-full border border-dashed hover:opacity-95'
              >
                {preview ? (
                  <img src={preview} alt='avatar preview' className='h-full w-full object-cover' />
                ) : (
                  <ImageIcon />
                )}
              </div>

              <div className='flex items-center gap-2'>
                <input ref={inputRef} type='file' accept='image/*' className='hidden' onChange={onSelect} />
                <Button type='button' variant='outline' onClick={openPicker} className='flex items-center gap-2'>
                  <UploadCloudIcon />
                  Upload avatar
                </Button>
                <Button type='button' variant='ghost' onClick={remove} disabled={!file} className='text-destructive!'>
                  <TrashIcon />
                </Button>
              </div>
            </div>
            <p className='text-muted-foreground text-sm'>Pick a photo up to 1MB.</p>
          </div>
          <div className='grid grid-cols-1 gap-6 sm:grid-cols-2'>
            <div className='flex flex-col items-start gap-2'>
              <Label htmlFor='multi-step-personal-info-first-name'>First Name</Label>
              <Input id='multi-step-personal-info-first-name' placeholder='John' />
            </div>
            <div className='flex flex-col items-start gap-2'>
              <Label htmlFor='multi-step-personal-info-last-name'>Last Name</Label>
              <Input id='multi-step-personal-info-last-name' placeholder='Doe' />
            </div>
            <div className='flex flex-col items-start gap-2'>
              <Label htmlFor='multi-step-personal-info-mobile'>Mobile</Label>
              <Input id='multi-step-personal-info-mobile' type='tel' placeholder='+1 (555) 123-4567' />
            </div>
            <div className='flex flex-col items-start gap-2'>
              <Label htmlFor='country'>Country</Label>
              <Select>
                <SelectTrigger
                  id='country'
                  className='[&>span_svg]:text-muted-foreground/80 w-full [&>span]:flex [&>span]:items-center [&>span]:gap-2 [&>span_svg]:shrink-0'
                >
                  <SelectValue placeholder='Select country' />
                </SelectTrigger>
                <SelectContent className='[&_*[role=option]>span>svg]:text-muted-foreground/80 max-h-100 [&_*[role=option]]:pr-8 [&_*[role=option]]:pl-2 [&_*[role=option]>span]:right-2 [&_*[role=option]>span]:left-auto [&_*[role=option]>span]:flex [&_*[role=option]>span]:items-center [&_*[role=option]>span]:gap-2 [&_*[role=option]>span>svg]:shrink-0'>
                  {countries.map(country => (
                    <SelectItem key={country.value} value={country.value}>
                      <img src={country.flag} alt={`${country.label} flag`} className='h-4 w-5' />{' '}
                      <span className='truncate'>{country.label}</span>
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            <div className='space-y-2'>
              <Label htmlFor='gender'>Gender</Label>
              <Select>
                <SelectTrigger id='gender' className='w-full'>
                  <SelectValue placeholder='Select a gender' />
                </SelectTrigger>
                <SelectContent>
                  <SelectGroup>
                    <SelectItem value='male'>Male</SelectItem>
                    <SelectItem value='female'>Female</SelectItem>
                    <SelectItem value='other'>Other</SelectItem>
                  </SelectGroup>
                </SelectContent>
              </Select>
            </div>

            <div className='space-y-2'>
              <Label htmlFor='role'>Role</Label>
              <Select>
                <SelectTrigger id='role' className='w-full'>
                  <SelectValue placeholder='Select a role' />
                </SelectTrigger>
                <SelectContent>
                  <SelectGroup>
                    <SelectItem value='admin'>Admin</SelectItem>
                    <SelectItem value='user'>User</SelectItem>
                    <SelectItem value='other'>Other</SelectItem>
                  </SelectGroup>
                </SelectContent>
              </Select>
            </div>
          </div>
        </form>
        <div className='flex justify-end'>
          <Button type='submit' className='max-sm:w-full'>
            Save Changes
          </Button>
        </div>
      </div>
    </div>
  )
}

export default PersonalInfo
```

### `src/registry/new-york/components/blocks/account-settings-01/content/social-url.tsx`

```tsx
'use client'

import { useState } from 'react'

import { PlusIcon } from 'lucide-react'

import { Input } from '@/registry/new-york/ui/input'
import { Button } from '@/registry/new-york/ui/button'

const SocialUrl = () => {
  const [urls, setUrls] = useState<string[]>(['', '', ''])

  const addUrl = () => setUrls(prev => [...prev, ''])

  const updateUrl = (index: number, value: string) => setUrls(prev => prev.map((u, i) => (i === index ? value : u)))

  return (
    <div className='grid grid-cols-1 gap-10 lg:grid-cols-3'>
      {/* Vertical Tabs List */}
      <div className='flex flex-col'>
        <h3 className='text-foreground font-semibold'>Social URLs</h3>
        <p className='text-muted-foreground text-sm'>Manage your social URLs.</p>
      </div>

      {/* Content */}
      <div className='space-y-6 lg:col-span-2'>
        <div className='space-y-4'>
          {urls.map((url, idx) => (
            <Input
              key={idx}
              type='text'
              placeholder='Link to social profile'
              value={url}
              onChange={e => updateUrl(idx, e.target.value)}
            />
          ))}
        </div>
        <div className='flex items-center justify-between gap-4'>
          <Button type='button' variant='outline' onClick={addUrl}>
            <PlusIcon className='size-4' />
            Add URL
          </Button>
          <Button type='submit'>Save Changes</Button>
        </div>
      </div>
    </div>
  )
}

export default SocialUrl
```
