Button Group
Um contêiner que agrupa botões relacionados com estilização consistente.
"use client";
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@blips/ui/components/dropdown-menu";
import {
Archive,
ArrowLeft,
CalendarPlus,
Clock,
Funnel,
EnvelopeSimple,
DotsThree,
Tag,
Trash,
} from "@phosphor-icons/react";
import * as React from "react";
export default function ButtonGroupDemo() {
const [label, setLabel] = React.useState("personal");
return (
<ButtonGroup>
<ButtonGroup className="hidden sm:flex">
<Button variant="outline" size="icon" aria-label="Go Back">
<ArrowLeft />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Archive</Button>
<Button variant="outline">Report</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Snooze</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon" aria-label="More Options">
<DotsThree />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-52">
<DropdownMenuGroup>
<DropdownMenuItem>
<EnvelopeSimple />
Mark as Read
</DropdownMenuItem>
<DropdownMenuItem>
<Archive />
Archive
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<Clock />
Snooze
</DropdownMenuItem>
<DropdownMenuItem>
<CalendarPlus />
Add to Calendar
</DropdownMenuItem>
<DropdownMenuItem>
<Funnel />
Add to List
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Tag />
Label As...
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuRadioGroup
value={label}
onValueChange={setLabel}
>
<DropdownMenuRadioItem value="personal">
Personal
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="work">
Work
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="other">
Other
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<Trash />
Trash
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
</ButtonGroup>
);
}
Instalação
Uso
import {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
} from "@blips/ui/components/button-group"<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>Acessibilidade
- O componente
ButtonGrouptem o atributoroledefinido comogroup. - Use
Tabpara navegar entre os botões do grupo. - Use
aria-labelouaria-labelledbypara rotular o grupo de botões.
<ButtonGroup aria-label="Button group">
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>ButtonGroup vs ToggleGroup
- Use o componente
ButtonGroupquando quiser agrupar botões que executam uma ação. - Use o componente
ToggleGroupquando quiser agrupar botões que alternam um estado.
Exemplos
Orientação
Defina a prop orientation para alterar o layout do grupo de botões.
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import { Minus, Plus } from "@phosphor-icons/react";
export default function ButtonGroupOrientation() {
return (
<ButtonGroup
orientation="vertical"
aria-label="Media controls"
className="h-fit"
>
<Button variant="outline" size="icon">
<Plus />
</Button>
<Button variant="outline" size="icon">
<Minus />
</Button>
</ButtonGroup>
);
}
Tamanho
Controle o tamanho dos botões usando a prop size em cada botão.
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import { Plus } from "@phosphor-icons/react";
export default function ButtonGroupSize() {
return (
<div className="flex flex-col items-start gap-8">
<ButtonGroup>
<Button variant="outline" size="sm">
Small
</Button>
<Button variant="outline" size="sm">
Button
</Button>
<Button variant="outline" size="sm">
Group
</Button>
<Button variant="outline" size="icon-sm">
<Plus />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Default</Button>
<Button variant="outline">Button</Button>
<Button variant="outline">Group</Button>
<Button variant="outline" size="icon">
<Plus />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="lg">
Large
</Button>
<Button variant="outline" size="lg">
Button
</Button>
<Button variant="outline" size="lg">
Group
</Button>
<Button variant="outline" size="icon-lg">
<Plus />
</Button>
</ButtonGroup>
</div>
);
}
Aninhado
Aninhe componentes <ButtonGroup> para criar grupos de botões com espaçamento.
"use client";
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import { ArrowLeft, ArrowRight } from "@phosphor-icons/react";
export default function ButtonGroupNested() {
return (
<ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="sm">
1
</Button>
<Button variant="outline" size="sm">
2
</Button>
<Button variant="outline" size="sm">
3
</Button>
<Button variant="outline" size="sm">
4
</Button>
<Button variant="outline" size="sm">
5
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="icon-sm" aria-label="Previous">
<ArrowLeft />
</Button>
<Button variant="outline" size="icon-sm" aria-label="Next">
<ArrowRight />
</Button>
</ButtonGroup>
</ButtonGroup>
);
}
Separador
O componente ButtonGroupSeparator divide visualmente os botões dentro de um grupo.
import { Button } from "@blips/ui/components/button";
import {
ButtonGroup,
ButtonGroupSeparator,
} from "@blips/ui/components/button-group";
export default function ButtonGroupSeparatorDemo() {
return (
<ButtonGroup>
<Button variant="secondary" size="sm">
Copy
</Button>
<ButtonGroupSeparator />
<Button variant="secondary" size="sm">
Paste
</Button>
</ButtonGroup>
);
}
Split
Crie um grupo de botões split adicionando dois botões separados por um ButtonGroupSeparator.
import { Button } from "@blips/ui/components/button";
import {
ButtonGroup,
ButtonGroupSeparator,
} from "@blips/ui/components/button-group";
import { Plus } from "@phosphor-icons/react";
export default function ButtonGroupSplit() {
return (
<ButtonGroup>
<Button variant="secondary">Button</Button>
<ButtonGroupSeparator />
<Button size="icon" variant="secondary">
<Plus />
</Button>
</ButtonGroup>
);
}
Input
Envolva um componente Input com botões.
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import { Input } from "@blips/ui/components/input";
import { MagnifyingGlass } from "@phosphor-icons/react";
export default function ButtonGroupInput() {
return (
<ButtonGroup>
<Input placeholder="MagnifyingGlass..." />
<Button variant="outline" aria-label="MagnifyingGlass">
<MagnifyingGlass />
</Button>
</ButtonGroup>
);
}
Input Group
Envolva um componente InputGroup para criar layouts de entrada elaborados.
"use client";
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
} from "@blips/ui/components/input-group";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@blips/ui/components/tooltip";
import { Waveform, Plus } from "@phosphor-icons/react";
import * as React from "react";
export default function ButtonGroupInputGroup() {
const [voiceEnabled, setVoiceEnabled] = React.useState(false);
return (
<ButtonGroup className="[--radius:9999rem]">
<ButtonGroup>
<Button variant="outline" size="icon">
<Plus />
</Button>
</ButtonGroup>
<ButtonGroup>
<InputGroup>
<InputGroupInput
placeholder={
voiceEnabled ? "Record and send audio..." : "Send a message..."
}
disabled={voiceEnabled}
/>
<InputGroupAddon align="inline-end">
<Tooltip>
<TooltipTrigger asChild>
<InputGroupButton
onClick={() => setVoiceEnabled(!voiceEnabled)}
size="icon-xs"
data-active={voiceEnabled}
className="data-[active=true]:bg-orange-100 data-[active=true]:text-orange-700 dark:data-[active=true]:bg-orange-800 dark:data-[active=true]:text-orange-100"
aria-pressed={voiceEnabled}
>
<Waveform />
</InputGroupButton>
</TooltipTrigger>
<TooltipContent>Voice Mode</TooltipContent>
</Tooltip>
</InputGroupAddon>
</InputGroup>
</ButtonGroup>
</ButtonGroup>
);
}
Dropdown Menu
Crie um grupo de botões split com um componente DropdownMenu.
"use client";
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@blips/ui/components/dropdown-menu";
import {
Warning,
Check,
CaretDown,
Copy,
ShareNetwork,
Trash,
UserMinus,
SpeakerSimpleX,
} from "@phosphor-icons/react";
export default function ButtonGroupDropdown() {
return (
<ButtonGroup>
<Button variant="outline">Follow</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="pl-2!">
<CaretDown />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="[--radius:1rem]">
<DropdownMenuGroup>
<DropdownMenuItem>
<SpeakerSimpleX />
Mute Conversation
</DropdownMenuItem>
<DropdownMenuItem>
<Check />
Mark as Read
</DropdownMenuItem>
<DropdownMenuItem>
<Warning />
Report Conversation
</DropdownMenuItem>
<DropdownMenuItem>
<UserMinus />
Block User
</DropdownMenuItem>
<DropdownMenuItem>
<ShareNetwork />
Share Conversation
</DropdownMenuItem>
<DropdownMenuItem>
<Copy />
Copy Conversation
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<Trash />
Delete Conversation
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
);
}
Select
Combine com um componente Select.
"use client";
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import { Input } from "@blips/ui/components/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
} from "@blips/ui/components/select";
import { ArrowRight } from "@phosphor-icons/react";
import * as React from "react";
const CURRENCIES = [
{
value: "$",
label: "US Dollar",
},
{
value: "€",
label: "Euro",
},
{
value: "£",
label: "British Pound",
},
];
export default function ButtonGroupSelect() {
const [currency, setCurrency] = React.useState("$");
return (
<ButtonGroup>
<ButtonGroup>
<Select value={currency} onValueChange={setCurrency}>
<SelectTrigger className="font-mono">{currency}</SelectTrigger>
<SelectContent className="min-w-24">
{CURRENCIES.map((currency) => (
<SelectItem key={currency.value} value={currency.value}>
{currency.value}{" "}
<span className="text-muted-foreground">{currency.label}</span>
</SelectItem>
))}
</SelectContent>
</Select>
<Input placeholder="10.00" pattern="[0-9]*" />
</ButtonGroup>
<ButtonGroup>
<Button aria-label="Send" size="icon" variant="outline">
<ArrowRight />
</Button>
</ButtonGroup>
</ButtonGroup>
);
}
Popover
Use com um componente Popover.
import { Button } from "@blips/ui/components/button";
import { ButtonGroup } from "@blips/ui/components/button-group";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@blips/ui/components/popover";
import { Separator } from "@blips/ui/components/separator";
import { Textarea } from "@blips/ui/components/textarea";
import { Robot, CaretDown } from "@phosphor-icons/react";
export default function ButtonGroupPopover() {
return (
<ButtonGroup>
<Button variant="outline">
<Robot /> Copilot
</Button>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" size="icon" aria-label="Open Popover">
<CaretDown />
</Button>
</PopoverTrigger>
<PopoverContent align="end" className="rounded-xl p-0 text-sm">
<div className="px-4 py-3">
<div className="text-sm font-medium">Agent Tasks</div>
</div>
<Separator />
<div className="p-4 text-sm *:[p:not(:last-child)]:mb-2">
<Textarea
placeholder="Describe your task in natural language."
className="mb-4 resize-none"
/>
<p className="font-medium">Start a new task with Copilot</p>
<p className="text-muted-foreground">
Describe your task in natural language. Copilot will work in the
background and open a pull request for your review.
</p>
</div>
</PopoverContent>
</Popover>
</ButtonGroup>
);
}
Referência da API
ButtonGroup
O componente ButtonGroup é um contêiner que agrupa botões relacionados com estilização consistente.
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>Aninhe múltiplos grupos de botões para criar layouts elaborados com espaçamento. Veja o exemplo nested para mais detalhes.
<ButtonGroup>
<ButtonGroup />
<ButtonGroup />
</ButtonGroup>ButtonGroupSeparator
O componente ButtonGroupSeparator divide visualmente os botões dentro de um grupo.
<ButtonGroup>
<Button>Button 1</Button>
<ButtonGroupSeparator />
<Button>Button 2</Button>
</ButtonGroup>ButtonGroupText
Use este componente para exibir texto dentro de um grupo de botões.
<ButtonGroup>
<ButtonGroupText>Text</ButtonGroupText>
<Button>Button</Button>
</ButtonGroup>Use a prop asChild para renderizar um componente personalizado como texto, por exemplo um label.
import { ButtonGroupText } from "@blips/ui/components/button-group"
import { Label } from "@blips/ui/components/label"
export function ButtonGroupTextDemo() {
return (
<ButtonGroup>
<ButtonGroupText asChild>
<Label htmlFor="name">Text</Label>
</ButtonGroupText>
<Input placeholder="Digite algo aqui..." id="name" />
</ButtonGroup>
)
}