- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Auth Surface
- Avatar
- Badge
- Browse Catalog Dialog
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Connector Setup Dialog
- Cookie Banner
- Dialog
- Directory Card
- Directory Detail
- Directory Skeleton
- DrawerНовое
- Token Parts Input
- Empty
- Field
- Fieldset
- File Preview Modal
- File Preview Skeleton
- Form
- Frame
- Group
- Icon
- Input
- Input Group
- Kbd
- Label
- Legal Shell
- Menu
- Mermaid Diagram
- Mind Map Diagram
- Not Found Screen
- Onboarding Frame
- Popover
- PDF Thumbnail
- Personalization Landing
- Preview Card
- Pricing Page
- Progress
- Radio Group
- Ring Spinner
- Scroll Area
- Select
- Separator
- Settings Page
- Settings Skills
- Settings Connectors
- Settings Capabilities
- Settings Usage
- Settings Account
- Settings Billing
- Sheet
- Sidebar
- Skeleton
- Skill Create Dialog
- Slider
- Spinner
- Stat
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Tooltip
- Компоненты AI
- Chat Conversation
- Chat Message
- Chat Response
- Chat Suggestion
- Chat Prompt Input
- Slash Highlighted Textarea
- Chat Search Dialog
- Chat Skill Doc
- Chat Connector Detail
- Chat Attachments
- Chat File Card
- Chat Token Chip
- Chat Code Block
- Chat Image
- Chat Inline Citation
- Chat Sources
- Chat Web Search
- Chat Research
- Chat Source
- Chat Actions
- Chat Context
- Chat Loader
- Chat Compaction
- Chat Timeline
- Chat Snippet
- Chat Terminal
- Chat Stack Trace
- Chat Test Results
- Chat File Tree
- Chat Environment Variables
- Chat Audio Player
- Chat Transcription
- Chat Speech Input
- Chat Mic Selector
- Chat Voice Selector
- Chat Agent
- Chat Persona
- Chat Connection
- Chat Connector Suggestion
- Chat Queue
- Chat Checkpoint
- Chat Confirmation
- Chat Artifact
- Chat JSX Preview
- Chat Schema Display
- Chat Package Info
- Chat Commit
- Chat Plan
- Chat Open In Chat
- Chat Sandbox
- Chat Model Selector
- Chat Canvas
- Chat Node
- Chat Edge
Group
Компонент для визуальной группировки ряда элементов управления.
import {
IconArchive,
IconDots,
IconEdit,
IconFiles,
IconMovie,
IconShare,
IconTrash,
} from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Group aria-label="Действия с файлами">
<Button variant="outline">
<IconFiles aria-hidden="true" stroke={1.5} />
Файлы
</Button>
<GroupSeparator />
<Button variant="outline">
<IconMovie aria-hidden="true" stroke={1.5} />
Медиа
</Button>
<GroupSeparator />
<Menu>
<MenuTrigger
render={<Button aria-label="Меню" size="icon" variant="outline" />}
>
<IconDots className="size-4" stroke={1.5} />
</MenuTrigger>
<MenuPopup align="end">
<MenuItem>
<IconEdit aria-hidden="true" stroke={1.5} />
Редактировать
</MenuItem>
<MenuItem>
<IconArchive aria-hidden="true" stroke={1.5} />В архив
</MenuItem>
<MenuItem>
<IconShare aria-hidden="true" stroke={1.5} />
Поделиться
</MenuItem>
<MenuItem variant="destructive">
<IconTrash aria-hidden="true" stroke={1.5} />
Удалить
</MenuItem>
</MenuPopup>
</Menu>
</Group>
);
}
Установка
pnpm dlx shadcn@latest add @oracul/group
Использование
import { Button } from "@/components/ui/button"
import { Group, GroupSeparator } from "@/components/ui/group"<Group>
<Button>Button</Button>
<GroupSeparator />
<Button>Button</Button>
</Group>Доступность
- У компонента
Groupатрибутroleустановлен в значениеgroup. - Используйте
Tabдля перемещения между элементами управления внутри группы. - Используйте
aria-labelилиaria-labelledby, чтобы пометить группу.
<Group aria-label="Управление воспроизведением">
<Button variant="outline">Play</Button>
<GroupSeparator />
<Button variant="outline">Pause</Button>
</Group>Group против ToggleGroup
- Используйте компонент
Group, когда нужно сгруппировать элементы управления, выполняющие действие. - Используйте компонент
ToggleGroup, когда нужно сгруппировать элементы управления, переключающие состояние.
Справочник API
Group
Компонент Group — это контейнер, который визуально объединяет ряд связанных элементов управления с единообразным оформлением.
| Свойство | Тип | По умолчанию |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
<Group>
<Button>Button 1</Button>
<GroupSeparator />
<Button>Button 2</Button>
</Group>Вкладывайте несколько групп друг в друга, чтобы создавать сложные раскладки с отступами. Подробнее см. пример вложенные группы.
<Group>
<Group>
<Button>1</Button>
<GroupSeparator />
<Button>2</Button>
</Group>
<Group>
<Button>Previous</Button>
<GroupSeparator />
<Button>Next</Button>
</Group>
</Group>GroupSeparator
Компонент GroupSeparator визуально разделяет элементы управления внутри группы.
| Свойство | Тип | По умолчанию |
|---|---|---|
orientation | "horizontal" | "vertical" | "vertical" |
<Group>
<Button>Button 1</Button>
<GroupSeparator />
<Button>Button 2</Button>
</Group>Заметка: В отличие от ButtonGroup из shadcn, GroupSeparator обязателен между всеми элементами управления, включая кнопки в стиле outline. Это обеспечивает единообразную визуальную иерархию и состояния фокуса.
GroupText
Используйте этот компонент для отображения текста внутри группы, например меток или префиксов.
| Свойство | Тип | По умолчанию |
|---|---|---|
render | React.ReactNode | null | null |
<Group>
<GroupText>https://</GroupText>
<GroupSeparator />
<Input placeholder="example.com" />
</Group>Используйте свойство render, чтобы отрисовать пользовательский компонент в качестве текста, например метку.
<Group>
<GroupText render={<Label htmlFor="domain" aria-label="Domain" />}>
https://
</GroupText>
<GroupSeparator />
<Input id="domain" placeholder="example.com" />
</Group>Примеры
С полем ввода
"use client";
import { IconCheck, IconCopy } from "@tabler/icons-react";
import { useRef } from "react";
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import { Input } from "@/components/ui/input";
import {
Tooltip,
TooltipPopup,
TooltipTrigger,
} from "@/components/ui/tooltip";
export default function Particle() {
const { copyToClipboard, isCopied } = useCopyToClipboard();
const inputRef = useRef<HTMLInputElement>(null);
return (
<Group aria-label="Ввод URL">
<Input
aria-label="URL"
defaultValue="https://localhost:4001"
ref={inputRef}
type="text"
/>
<GroupSeparator />
<Tooltip>
<TooltipTrigger
render={
<Button
aria-label="Скопировать"
onClick={() => {
if (inputRef.current) {
copyToClipboard(inputRef.current.value);
}
}}
size="icon"
variant="outline"
/>
}
>
{isCopied ? <IconCheck stroke={1.5} /> : <IconCopy stroke={1.5} />}
</TooltipTrigger>
<TooltipPopup>
<p>Скопировать в буфер обмена</p>
</TooltipPopup>
</Tooltip>
</Group>
);
}
Маленький размер
import {
IconArchive,
IconDots,
IconEdit,
IconFiles,
IconMovie,
IconShare,
IconTrash,
} from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Group aria-label="Действия с файлами">
<Button size="sm" variant="outline">
<IconFiles aria-hidden="true" stroke={1.5} />
Файлы
</Button>
<GroupSeparator />
<Button size="sm" variant="outline">
<IconMovie aria-hidden="true" stroke={1.5} />
Медиа
</Button>
<GroupSeparator />
<Menu>
<MenuTrigger
render={<Button aria-label="Меню" size="icon-sm" variant="outline" />}
>
<IconDots aria-hidden="true" className="size-4" stroke={1.5} />
</MenuTrigger>
<MenuPopup align="end">
<MenuItem>
<IconEdit aria-hidden="true" stroke={1.5} />
Редактировать
</MenuItem>
<MenuItem>
<IconArchive aria-hidden="true" stroke={1.5} />В архив
</MenuItem>
<MenuItem>
<IconShare aria-hidden="true" stroke={1.5} />
Поделиться
</MenuItem>
<MenuItem variant="destructive">
<IconTrash aria-hidden="true" stroke={1.5} />
Удалить
</MenuItem>
</MenuPopup>
</Menu>
</Group>
);
}
Большой размер
import {
IconArchive,
IconDots,
IconEdit,
IconFiles,
IconMovie,
IconShare,
IconTrash,
} from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Group aria-label="Действия с файлами">
<Button size="lg" variant="outline">
<IconFiles aria-hidden="true" stroke={1.5} />
Файлы
</Button>
<GroupSeparator />
<Button size="lg" variant="outline">
<IconMovie aria-hidden="true" stroke={1.5} />
Медиа
</Button>
<GroupSeparator />
<Menu>
<MenuTrigger
render={<Button aria-label="Меню" size="icon-lg" variant="outline" />}
>
<IconDots aria-hidden="true" className="size-4" stroke={1.5} />
</MenuTrigger>
<MenuPopup align="end">
<MenuItem>
<IconEdit aria-hidden="true" stroke={1.5} />
Редактировать
</MenuItem>
<MenuItem>
<IconArchive aria-hidden="true" stroke={1.5} />В архив
</MenuItem>
<MenuItem>
<IconShare aria-hidden="true" stroke={1.5} />
Поделиться
</MenuItem>
<MenuItem variant="destructive">
<IconTrash aria-hidden="true" stroke={1.5} />
Удалить
</MenuItem>
</MenuPopup>
</Menu>
</Group>
);
}
С отключённой кнопкой
import {
IconArchive,
IconDots,
IconEdit,
IconFiles,
IconMovie,
IconShare,
IconTrash,
} from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Group aria-label="Действия с файлами">
<Button variant="outline">
<IconFiles aria-hidden="true" stroke={1.5} />
Файлы
</Button>
<GroupSeparator />
<Button disabled variant="outline">
<IconMovie aria-hidden="true" stroke={1.5} />
Медиа
</Button>
<GroupSeparator />
<Menu>
<MenuTrigger
render={<Button aria-label="Меню" size="icon" variant="outline" />}
>
<IconDots aria-hidden="true" className="size-4" stroke={1.5} />
</MenuTrigger>
<MenuPopup align="end">
<MenuItem>
<IconEdit aria-hidden="true" stroke={1.5} />
Редактировать
</MenuItem>
<MenuItem>
<IconArchive aria-hidden="true" stroke={1.5} />В архив
</MenuItem>
<MenuItem>
<IconShare aria-hidden="true" stroke={1.5} />
Поделиться
</MenuItem>
<MenuItem variant="destructive">
<IconTrash aria-hidden="true" stroke={1.5} />
Удалить
</MenuItem>
</MenuPopup>
</Menu>
</Group>
);
}
С кнопками по умолчанию
import {
IconArchive,
IconDots,
IconEdit,
IconFiles,
IconMovie,
IconShare,
IconTrash,
} from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Group aria-label="Действия с файлами">
<Button>
<IconFiles aria-hidden="true" stroke={1.5} />
Файлы
</Button>
<GroupSeparator className="bg-primary/72" />
<Button>
<IconMovie aria-hidden="true" stroke={1.5} />
Медиа
</Button>
<GroupSeparator className="bg-primary/72" />
<Menu>
<MenuTrigger render={<Button aria-label="Меню" size="icon" />}>
<IconDots aria-hidden="true" className="size-4" stroke={1.5} />
</MenuTrigger>
<MenuPopup align="end">
<MenuItem>
<IconEdit aria-hidden="true" stroke={1.5} />
Редактировать
</MenuItem>
<MenuItem>
<IconArchive aria-hidden="true" stroke={1.5} />В архив
</MenuItem>
<MenuItem>
<IconShare aria-hidden="true" stroke={1.5} />
Поделиться
</MenuItem>
<MenuItem variant="destructive">
<IconTrash aria-hidden="true" stroke={1.5} />
Удалить
</MenuItem>
</MenuPopup>
</Menu>
</Group>
);
}
С текстовой меткой в начале
import { Group, GroupSeparator, GroupText } from "@/components/ui/group";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export default function Particle() {
return (
<Group aria-label="Ввод домена">
<GroupText render={<Label aria-label="Домен" htmlFor="domain" />}>
https://
</GroupText>
<GroupSeparator />
<Input
aria-label="Домен"
defaultValue="localhost:4001"
id="domain"
type="text"
/>
</Group>
);
}
С текстом в конце
import { Group, GroupSeparator, GroupText } from "@/components/ui/group";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export default function Particle() {
return (
<Group aria-label="Ввод домена">
<Input
aria-label="Домен"
defaultValue="oracul"
id="domain-suffix"
type="text"
/>
<GroupSeparator />
<GroupText
render={<Label aria-label="Суффикс домена" htmlFor="domain-suffix" />}
>
.com
</GroupText>
</Group>
);
}
Вертикальная
import { IconZoomIn, IconZoomOut } from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
export default function Particle() {
return (
<Group aria-label="Управление масштабом" orientation="vertical">
<Button aria-label="Приблизить" size="icon" variant="outline">
<IconZoomIn stroke={1.5} />
</Button>
<GroupSeparator orientation="horizontal" />
<Button aria-label="Отдалить" size="icon" variant="outline">
<IconZoomOut stroke={1.5} />
</Button>
</Group>
);
}
Вложенные группы
import { IconArrowLeft, IconArrowRight } from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
export default function Particle() {
return (
<Group aria-label="Пагинация">
<Group aria-label="Номера страниц">
<Button className="min-w-8" variant="outline">
1
</Button>
<GroupSeparator />
<Button className="min-w-8" variant="outline">
2
</Button>
<GroupSeparator />
<Button className="min-w-8" variant="outline">
3
</Button>
<GroupSeparator />
<Button className="min-w-8" variant="outline">
4
</Button>
<GroupSeparator />
<Button className="min-w-8" variant="outline">
5
</Button>
</Group>
<Group aria-label="Навигация">
<Button aria-label="Назад" size="icon" variant="outline">
<IconArrowLeft aria-hidden="true" stroke={1.5} />
</Button>
<GroupSeparator />
<Button aria-label="Вперёд" size="icon" variant="outline">
<IconArrowRight aria-hidden="true" stroke={1.5} />
</Button>
</Group>
</Group>
);
}
С всплывающим окном
import { IconChevronDown, IconGitFork } from "@tabler/icons-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Popover,
PopoverDescription,
PopoverPopup,
PopoverTitle,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Particle() {
return (
<Group aria-label="Действия с репозиторием">
<Button variant="outline">
<IconGitFork aria-hidden="true" stroke={1.5} />
Форк
<Badge variant="secondary">48</Badge>
</Button>
<GroupSeparator />
<Popover>
<PopoverTrigger
render={
<Button aria-label="Параметры" size="icon" variant="outline" />
}
>
<IconChevronDown aria-hidden="true" stroke={1.5} />
</PopoverTrigger>
<PopoverPopup align="end" className="w-64">
<PopoverTitle className="text-base">Существующие форки</PopoverTitle>
<PopoverDescription>
У вас нет форков этого репозитория.
</PopoverDescription>
</PopoverPopup>
</Popover>
</Group>
);
}
С группой полей ввода
import { IconMicrophone, IconPaperclip } from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group } from "@/components/ui/group";
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
export default function Particle() {
return (
<Group
aria-label="Создание сообщения"
className="[--radius-lg:9999px] [--radius:9999rem]"
>
<Group aria-label="Вложения">
<Button aria-label="Прикрепить файл" size="icon" variant="outline">
<IconPaperclip aria-hidden="true" stroke={1.5} />
</Button>
</Group>
<Group aria-label="Поле сообщения">
<InputGroup>
<InputGroupInput placeholder="Напишите сообщение" />
<InputGroupAddon align="inline-end">
<Tooltip>
<TooltipTrigger
render={
<Button
aria-label="Голосовой режим"
size="icon-xs"
variant="ghost"
/>
}
>
<IconMicrophone aria-hidden="true" stroke={1.5} />
</TooltipTrigger>
<TooltipContent>Голосовой режим</TooltipContent>
</Tooltip>
</InputGroupAddon>
</InputGroup>
</Group>
</Group>
);
}
С меню
import {
IconChevronDown,
IconDownload,
IconEdit,
IconShare,
} from "@tabler/icons-react";
import { Button } from "@/components/ui/button";
import { Group, GroupSeparator } from "@/components/ui/group";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Group aria-label="Действия с подпиской">
<Button>Подписаться</Button>
<GroupSeparator className="bg-primary/72" />
<Menu>
<MenuTrigger render={<Button aria-label="Параметры" size="icon" />}>
<IconChevronDown aria-hidden="true" className="size-4" stroke={1.5} />
</MenuTrigger>
<MenuPopup align="end">
<MenuItem>
<IconShare aria-hidden="true" stroke={1.5} />
Поделиться ссылкой
</MenuItem>
<MenuItem>
<IconDownload aria-hidden="true" stroke={1.5} />
Скачать
</MenuItem>
<MenuItem>
<IconEdit aria-hidden="true" stroke={1.5} />
Дублировать
</MenuItem>
</MenuPopup>
</Menu>
</Group>
);
}
На этой странице