PettyUI/.firecrawl/kobalte-styling.md
Mats Bosson db906fd85a Fix linting config and package fields
- Replace .eslintrc.cjs with eslint.config.mjs (ESLint 9 flat config)
  using direct eslint-plugin-solid + @typescript-eslint/parser approach
- Add @typescript-eslint/parser to root devDependencies
- Add main/module/types top-level fields to packages/core/package.json
- Add resolve.conditions to packages/core/vite.config.ts
- Create packages/core/tsconfig.test.json for test type-checking
- Remove empty paths:{} from packages/core/tsconfig.json
2026-03-29 02:35:57 +07:00

6.8 KiB

Styling

Kobalte components are unstyled, allowing you to completely customize the look and feel. Bring your preferred styling solution (vanilla CSS, Tailwind, CSS-in-JS libraries, etc...).

Styling a component part

All components and their parts accept a class prop. This class will be passed through to the DOM element. You can style a component part by targeting the class that you provide.

index.tsxstyle.css

Copytsx
import { Popover as KPopover } from "@kobalte/core";
import "./style.css";

export const Popover = () => {
  return (
    <KPopover>
      <KPopover.Trigger class="popover__trigger">
        Open
      </KPopover.Trigger>
      <KPopover.Content class="popover__content">
        ...
      </KPopover.Content>
    </KPopover>
  );
};
Copytsx
import { Popover as KPopover } from "@kobalte/core";
import "./style.css";

export const Popover = () => {
  return (
    <KPopover>
      <KPopover.Trigger class="popover__trigger">
        Open
      </KPopover.Trigger>
      <KPopover.Content class="popover__content">
        ...
      </KPopover.Content>
    </KPopover>
  );
};

Styling a state

When a component or its parts can have multiple states, we automatically attach data-* attributes that represents the specific state. For example, a popover's trigger can have:

  • data-expanded — When the popover is expanded.
  • data-disabled — When the popover is disabled.

You can style a component state by targeting the data-* attributes added by Kobalte.

style.css

Copycss
.popover__trigger[data-disabled] {
  /* The popover trigger style when disabled. */
}
Copycss
.popover__trigger[data-disabled] {
  /* The popover trigger style when disabled. */
}

Using the TailwindCSS plugin

If you are using TailwindCSS, you can use the @kobalte/tailwindcss plugin to target Kobalte's data-* attributes with modifiers like ui-expanded:*.

Installation

npmyarnpnpm

Copybash
npm install @kobalte/tailwindcss
Copybash
npm install @kobalte/tailwindcss

Usage

Add the plugin to your tailwind.config.js :

Copyjs
/** @type {import('tailwindcss').Config} */
module.exports = {
	content: [],
	theme: {
		extend: {},
	},
	plugins: [\
		// default prefix is "ui"\
		require("@kobalte/tailwindcss"),\
\
		// or with a custom prefix:\
		require("@kobalte/tailwindcss")({ prefix: "kb" }),\
	],
};
Copyjs
/** @type {import('tailwindcss').Config} */
module.exports = {
	content: [],
	theme: {
		extend: {},
	},
	plugins: [\
		// default prefix is "ui"\
		require("@kobalte/tailwindcss"),\
\
		// or with a custom prefix:\
		require("@kobalte/tailwindcss")({ prefix: "kb" }),\
	],
};

Style your component:

Copytsx
import { Popover as KPopover } from "@kobalte/core/popover";

export const Popover = () => (
	<KPopover>
		<KPopover.Trigger class="inline-flex px-4 py-2 rounded ui-disabled:bg-slate-100">
			Open
		</KPopover.Trigger>
		<KPopover.Content class="flex p-4 rounded bg-white">...</KPopover.Content>
	</KPopover>
);
Copytsx
import { Popover as KPopover } from "@kobalte/core/popover";

export const Popover = () => (
	<KPopover>
		<KPopover.Trigger class="inline-flex px-4 py-2 rounded ui-disabled:bg-slate-100">
			Open
		</KPopover.Trigger>
		<KPopover.Content class="flex p-4 rounded bg-white">...</KPopover.Content>
	</KPopover>
);

You can use the following modifiers:

Modifier CSS Selector
ui-valid &[data-valid]
ui-invalid &[data-invalid]
ui-required &[data-required]
ui-disabled &[data-disabled]
ui-readonly &[data-readonly]
ui-checked &[data-checked]
ui-indeterminate &[data-indeterminate]
ui-selected &[data-selected]
ui-pressed &[data-pressed]
ui-expanded &[data-expanded]
ui-highlighted &[data-highlighted]
ui-current &[data-current]

It's also possible to use inverse modifiers in the form of ui-not-*, group and peer modifiers in the form of ui-group-* and ui-peer-*.

Using the Vanilla Extract plugin

If you are using Vanilla Extract, you can use the @kobalte/vanilla-extract plugin to target Kobalte's data-* attributes.

Installation

npmyarnpnpm

Copybash
npm install @kobalte/vanilla-extract
Copybash
npm install @kobalte/vanilla-extract

Usage

Use the componentStateStyles utility function to create vanilla-extract styles that target data-* attributes of Kobalte components.

Copyts
// styles.css
import { componentStateStyles } from "@kobalte/vanilla-extract";
import { style } from "@vanilla-extract/css";

const button = style([\
	{\
		background: "blue",\
		padding: "2px 6px",\
	},\
	componentStateStyles({\
		disabled: {\
			opacity: 0.4,\
		},\
		invalid: {\
			backgroundColor: "red",\
			not: {\
				backgroundColor: "yellow",\
			},\
		},\
	}),\
	componentStateStyles(\
		{\
			invalid: {\
				backgroundColor: "red",\
			},\
		},\
		{ parentSelector: "[data-theme=dark]" },\
	),\
]);
Copyts
// styles.css
import { componentStateStyles } from "@kobalte/vanilla-extract";
import { style } from "@vanilla-extract/css";

const button = style([\
	{\
		background: "blue",\
		padding: "2px 6px",\
	},\
	componentStateStyles({\
		disabled: {\
			opacity: 0.4,\
		},\
		invalid: {\
			backgroundColor: "red",\
			not: {\
				backgroundColor: "yellow",\
			},\
		},\
	}),\
	componentStateStyles(\
		{\
			invalid: {\
				backgroundColor: "red",\
			},\
		},\
		{ parentSelector: "[data-theme=dark]" },\
	),\
]);

Then apply your styles to the component:

Copytsx
import { Button } from "@kobalte/core/button";
import { button } from "./styles.css";

export const MyButton = () => <Button class={button}>...</Button>;
Copytsx
import { Button } from "@kobalte/core/button";
import { button } from "./styles.css";

export const MyButton = () => <Button class={button}>...</Button>;

Usage with UnoCSS

The UnoCSS preset made by the community can be used to achieve the same behavior of the TailwindCSS plugin.

Extending a component

Extending a component is done the same way you extend any SolidJS component.

Copytsx
import { Popover as KPopover } from "@kobalte/core/popover";
import { ComponentProps } from "solid-js";

export const PopoverTrigger = (props: ComponentProps<typeof KPopover.Trigger>) => {
	return <KPopover.Trigger {...props} />;
};
Copytsx
import { Popover as KPopover } from "@kobalte/core/popover";
import { ComponentProps } from "solid-js";

export const PopoverTrigger = (props: ComponentProps<typeof KPopover.Trigger>) => {
	return <KPopover.Trigger {...props} />;
};

Previous←Getting startedNextAnimation→