Tailwind Joined Buttons

Something that came up at work recently was joining buttons into a group. When joined, we wanted the buttons to have no border radius between them to achieve a nice visual aesthetic.

While we could override the classes for the first and last buttons in the group, a much simpler and elegant solution is building a simple Join component that handles the border radius for us.

./Join.tsx
import { twMerge } from "tailwind-merge"

export function Join({
  className,
  ...props
}: React.HTMLAtributes<HTMLDivElement>) {
  return (
    <div
      className={twMerge(
        "flex [&>:not(:first-child)]:rounded-l-none [&>:not(:last-child)]:rounded-r-none gap-px",
        className,
      )}
      {...props}
    />
  )
}

Most of this snippet is just boilerplate, but the class name is what does the work. The resulting CSS looks something like this:

.flex > :not(:first-child) {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.flex > :not(:last-child) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

Now, we can use the Join component to join buttons together:

import { Join } from "./Join"

export function MyComponent() {
  return (
    <Join>
      <Button>Save</Button>
      <Button>
        <Icon name="more" />
      </Button>
    </Join>
  )
}

With this code, the result looks something like this:

example