Skip to content

feat(styled kit): collapsible component #1102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fair-women-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik-ui/styled': patch
---

FEAT: The styled kit Collapsible component is now available.
4 changes: 2 additions & 2 deletions apps/website/src/components/highlight/highlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type HighlightProps = PropsOf<'div'> & {
export const Highlight = component$(
({ code, copyCodeClass, language = 'tsx', ...props }: HighlightProps) => {
return (
<div class="code-example data-pagefind-ignore relative max-h-[31.25rem] rounded-base">
<div class="code-example data-pagefind-ignore relative rounded-base">
<CodeCopy
class={[
'absolute right-3 top-3 text-white hover:bg-slate-800 hover:text-white',
Expand All @@ -32,7 +32,7 @@ export const Highlight = component$(
<div
{...props}
class={cn(
'tab-size max-h-[31.25rem] max-w-full overflow-auto rounded-sm bg-gradient-to-b from-slate-900 to-slate-800 p-6 text-sm dark:from-background dark:to-accent/30',
'tab-size max-h-[494px] max-w-full overflow-auto rounded-sm bg-gradient-to-b from-slate-900 to-slate-800 p-6 text-sm dark:from-background dark:to-accent/30',
props.class,
)}
data-pagefind-ignore="all"
Expand Down
4 changes: 2 additions & 2 deletions apps/website/src/components/showcase/showcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export const Showcase = component$<ShowcaseProps>(({ rawCode, ...props }) => {
Code
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel class="rounded-b-md border px-8 py-32 md:px-32">
<section class="flex flex-col items-center">
<Tabs.Panel class="h-[500px] rounded-b-md border px-8 py-32 md:px-32">
<section class="flex h-full flex-col items-center justify-center">
<Slot />
</section>
</Tabs.Panel>
Expand Down
26 changes: 8 additions & 18 deletions apps/website/src/routes/docs/headless/collapsible/auto-api/api.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
export const api = {
collapsible: [
"collapsible": [
{
'collapsible-content': [],
"collapsible-content": []
},
{
'collapsible-trigger': [],
"collapsible-trigger": []
},
{
collapsible: [
{
CollapsibleProps: [
{
comment: '@deprecated use `onChange$` instead',
prop: 'onOpenChange$',
type: 'QRL<(open: boolean) => void>',
},
],
},
],
"collapsible": []
},
{
'use-collapsible': [],
},
],
};
"use-collapsible": []
}
]
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { LuChevronUp } from '@qwikest/icons/lucide';
export default component$(() => {
return (
<Carousel.Root
class="w-full"
class="w-full max-w-sm"
orientation="vertical"
maxSlideHeight={360}
slidesPerView={3}
Expand All @@ -17,7 +17,7 @@ export default component$(() => {
<div class="p-1">
<Card.Root>
<Card.Content class="flex w-full items-center justify-center pt-6">
<span class="text-4xl font-semibold">{index + 1}</span>
<span class="text-3xl font-semibold">{index + 1}</span>
</Card.Content>
</Card.Root>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Card, Carousel } from '@qwik-ui/styled';

export default component$(() => {
return (
<Carousel.Root class="max-w-xs sm:max-w-sm">
<Carousel.Root class="max-w-xs">
<Carousel.Scroller class="m-2">
{Array.from({ length: 9 }).map((_, index) => (
<Carousel.Slide key={index}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Card, Carousel } from '@qwik-ui/styled';

export default component$(() => {
return (
<Carousel.Root class="max-w-xs sm:max-w-sm">
<Carousel.Root class="max-w-xs">
<Carousel.Scroller>
{Array.from({ length: 5 }).map((_, index) => (
<Carousel.Slide key={index}>
Expand Down
30 changes: 30 additions & 0 deletions apps/website/src/routes/docs/styled/collapsible/examples/hero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { component$ } from '@builder.io/qwik';
import { cn } from '@qwik-ui/utils';
import { LuChevronsUpDown } from '@qwikest/icons/lucide';
import { buttonVariants, Collapsible } from '~/components/ui';

export default component$(() => {
return (
<Collapsible.Root class="flex w-[350px] flex-col gap-2">
<div class="flex items-center justify-between gap-4 px-4">
<h4 class="text-sm font-semibold">@peduarte starred 3 repositories</h4>
<Collapsible.Trigger
class={cn(buttonVariants({ size: 'icon', look: 'ghost' }), 'size-8')}
>
<LuChevronsUpDown />
</Collapsible.Trigger>
</div>
<div class="rounded-md border px-4 py-2 font-mono text-sm">@qwik-ui/headless</div>
<Collapsible.Content>
<div class="flex flex-col gap-2">
<div class="rounded-md border px-4 py-2 font-mono text-sm">
@qwik-ui/kit-styled
</div>
<div class="rounded-md border px-4 py-2 font-mono text-sm">
@qwik-ui/kit-headless
</div>
</div>
</Collapsible.Content>
</Collapsible.Root>
);
});
74 changes: 74 additions & 0 deletions apps/website/src/routes/docs/styled/collapsible/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: Qwik UI | Styled Collapsible Component
description: An interactive section that shows or hides its connected information. Copy/paste into your project from the documentation or by using the CLI. Easily customize the CVA variants according to your brand requirements.
---

import { statusByComponent } from '~/_state/component-statuses';

import { ShowcaseHero } from './showcase-components';


<StatusBanner status={statusByComponent.styled.Collapsible} />

# Collapsible

An interactive section that shows or hides its connected information.

<ShowcaseHero />

## Installation

### 1. Run the following cli command or copy/paste the component code into your project

```sh
qwik-ui add collapsible
```

```tsx
import { component$, Slot, type PropsOf } from '@builder.io/qwik';
import { Collapsible as HeadlessCollapsible } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';

const Root = (props: PropsOf<typeof HeadlessCollapsible.Root>) => (
<HeadlessCollapsible.Root {...props}>{props.children}</HeadlessCollapsible.Root>
);

const Trigger = component$<PropsOf<typeof HeadlessCollapsible.Trigger>>(
({ ...props }) => {
return (
<HeadlessCollapsible.Trigger {...props}>
<Slot />
</HeadlessCollapsible.Trigger>
);
},
);

const Content = component$<PropsOf<typeof HeadlessCollapsible.Content>>((props) => {
return (
<HeadlessCollapsible.Content {...props} class={cn(props.class)}>
<Slot />
</HeadlessCollapsible.Content>
);
});

export const Collapsible = {
Root,
Trigger,
Content,
};
```

## Usage

The styled Collapsible component doesn't isn't really styled because it's meant to be a wrapper around some items in a list or menu.

```tsx
import { Collapsible } from '~/components/ui';
```

```tsx
<Collapsible.Root>
<Collapsible.Trigger>Is it accessible?</Collapsible.Trigger>
<Collapsible.Content>Yes. It adheres to the WAI-ARIA design pattern.</Collapsible.Content>
</Collapsible.Root>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { component$ } from '@builder.io/qwik';
import { Showcase } from '~/components/showcase/showcase';

import Hero from './examples/hero';
import HeroRawCode from './examples/hero.tsx?raw';
export const ShowcaseHero = component$(() => {
return (
<Showcase rawCode={HeroRawCode}>
<Hero />
</Showcase>
);
});
1 change: 1 addition & 0 deletions apps/website/src/routes/docs/styled/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- [Card](/docs/styled/card)
- [Carousel](/docs/styled/carousel)
- [Checkbox](/docs/styled/checkbox)
- [Collapsible](/docs/styled/collapsible)
- [Combobox](/docs/styled/combobox)
- [Dropdown](/docs/styled/dropdown)
- [Input](/docs/styled/input)
Expand Down
12 changes: 12 additions & 0 deletions packages/kit-styled/components-registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
"componentFolder": "checkbox",
"files": ["checkbox.tsx"]
},
{
"displayName": "Collapsible",
"type": "collapsible",
"componentFolder": "collapsible",
"files": ["collapsible.tsx"]
},
{
"displayName": "Combobox",
"type": "combobox",
Expand Down Expand Up @@ -144,6 +150,12 @@
"type": "toggle-group",
"componentFolder": "toggle-group",
"files": ["toggle-group.tsx"]
},
{
"displayName": "Tooltip",
"type": "tooltip",
"componentFolder": "tooltip",
"files": ["tooltip.tsx"]
}
]
}

This file was deleted.

8 changes: 4 additions & 4 deletions packages/kit-styled/src/components/carousel/carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ const Previous = component$<
class={cn(
'absolute',
context.orientation === 'horizontal'
? '-left-16 top-1/2 -translate-y-1/2'
: '-top-16 right-1/2 translate-x-1/2',
? '-left-12 top-1/2 -translate-y-1/2'
: '-top-12 right-1/2 translate-x-1/2',
)}
>
<HCarousel.Previous
Expand Down Expand Up @@ -129,8 +129,8 @@ const Next = component$<
class={cn(
'absolute',
context.orientation === 'horizontal'
? '-right-16 top-1/2 -translate-y-1/2'
: '-bottom-16 right-1/2 translate-x-1/2',
? '-right-12 top-1/2 -translate-y-1/2'
: '-bottom-12 right-1/2 translate-x-1/2',
)}
>
{/* moves content to the right on hover */}
Expand Down
31 changes: 31 additions & 0 deletions packages/kit-styled/src/components/collapsible/collapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { component$, Slot, type PropsOf } from '@builder.io/qwik';
import { Collapsible as HeadlessCollapsible } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';

const Root = (props: PropsOf<typeof HeadlessCollapsible.Root>) => (
<HeadlessCollapsible.Root {...props}>{props.children}</HeadlessCollapsible.Root>
);

const Trigger = component$<PropsOf<typeof HeadlessCollapsible.Trigger>>(
({ ...props }) => {
return (
<HeadlessCollapsible.Trigger {...props}>
<Slot />
</HeadlessCollapsible.Trigger>
);
},
);

const Content = component$<PropsOf<typeof HeadlessCollapsible.Content>>((props) => {
return (
<HeadlessCollapsible.Content {...props} class={cn(props.class)}>
<Slot />
</HeadlessCollapsible.Content>
);
});

export const Collapsible = {
Root,
Trigger,
Content,
};
1 change: 1 addition & 0 deletions packages/kit-styled/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './components/button/button';
export * from './components/card/card';
export * from './components/carousel/carousel';
export * from './components/checkbox/checkbox';
export * from './components/collapsible/collapsible';
export * from './components/combobox/combobox';
export * from './components/input/input';
export * from './components/label/label';
Expand Down