Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/green-selects-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@cloudflare/kumo": patch
---

fix(select): align the trigger surface with form controls

Select triggers now use `bg-kumo-control`, including their open and disabled
states, so they match Input, Combobox, and the rest of the form-control family.
Consumer background classes can still override the default without using
`!important`. The popup remains on the floating `bg-kumo-base` surface.
54 changes: 54 additions & 0 deletions packages/kumo/src/components/select/select.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { act, fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vite-plus/test";
import { useState } from "react";
import { Input } from "../input/input";
import { Select } from "./select";

describe("Select", () => {
Expand All @@ -20,6 +21,57 @@ describe("Select", () => {
});
});

describe("surface styling", () => {
it("uses the same default surface color as Input", () => {
render(
<>
<Input aria-label="Text field" />
<Select aria-label="Select field">
<Select.Option value="a">Option A</Select.Option>
</Select>
</>,
);

const inputClasses = screen.getByRole("textbox").className.split(" ");
const selectClasses = screen.getByRole("combobox").className.split(" ");
const inputSurface = inputClasses.find((className) =>
className.startsWith("bg-kumo-"),
);
const selectSurface = selectClasses.find((className) =>
className.startsWith("bg-kumo-"),
);

expect(selectSurface).toBe(inputSurface);
});

it("does not revert to the Button surface when open or disabled", () => {
render(
<Select aria-label="Pick one" disabled>
<Select.Option value="a">Option A</Select.Option>
</Select>,
);

const trigger = screen.getByRole("combobox");
expect(trigger.className).toContain("data-[state=open]:bg-kumo-control");
expect(trigger.className).toContain("disabled:bg-kumo-control/50");
expect(trigger.className).not.toContain("data-[state=open]:bg-kumo-base");
expect(trigger.className).not.toContain("disabled:bg-kumo-base/50");
});

it("allows className to override the default surface without important", () => {
render(
<Select aria-label="Pick one" className="bg-kumo-elevated">
<Select.Option value="a">Option A</Select.Option>
</Select>,
);

const trigger = screen.getByRole("combobox");
const classes = trigger.className.split(" ");
expect(classes).toContain("bg-kumo-elevated");
expect(classes).not.toContain("bg-kumo-control");
});
});

describe("label visibility (new behavior)", () => {
it("shows visible label by default when label prop is provided", () => {
render(
Expand Down Expand Up @@ -597,6 +649,8 @@ describe("Select", () => {
const popup = listbox.parentElement;
expect(popup?.getAttribute("role")).toBe("presentation");
expect(popup?.className).toContain("max-h-[var(--available-height)]");
expect(popup?.className).toContain("bg-kumo-base");
expect(popup?.className).not.toContain("bg-kumo-control");
expect(popup?.className).not.toContain("overscroll");
});

Expand Down
5 changes: 3 additions & 2 deletions packages/kumo/src/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const KUMO_SELECT_STYLING = {
height: 36, // h-9
paddingX: 12, // px-3
borderRadius: 8, // rounded-lg
background: "bg-kumo-elevated",
background: "bg-kumo-control",
text: "text-color-surface",
ring: "color-border",
fontSize: 16, // text-base
Expand All @@ -46,7 +46,7 @@ export const KUMO_SELECT_STYLING = {
check: { name: "ph-check", size: 20 },
},
popup: {
background: "bg-kumo-elevated",
background: "bg-kumo-base",
ring: "border-kumo-line",
borderRadius: 8, // rounded-lg
padding: 6, // p-1.5
Expand Down Expand Up @@ -98,6 +98,7 @@ export function selectVariants({
}: KumoSelectVariantsProps = {}) {
return cn(
buttonVariants({ size }),
"bg-kumo-control disabled:bg-kumo-control/50 data-[state=open]:bg-kumo-control",
"justify-between font-normal",
"focus:opacity-100 focus:ring-kumo-focus/50 focus-visible:ring-inset *:in-focus:opacity-100",
);
Expand Down
Loading