Skip to content

Commit 4215ae3

Browse files
feat(combo-button): new web-component for parity (#19218)
* feat(combo-button): new web-component for parity * fix(combo-button): update docs * fix(combo-button): adjust alignment and trigger behavior * fix(combo-button): update story args and support tooltipAlignment * fix(combo-button): onclick * docs: update suggestions * Update packages/web-components/src/components/combo-button/combo-button.scss Co-authored-by: Ariella Gilmore <[email protected]> * Update packages/web-components/src/components/combo-button/combo-button.scss Co-authored-by: Ariella Gilmore <[email protected]> * Update packages/web-components/src/components/combo-button/combo-button.scss Co-authored-by: Ariella Gilmore <[email protected]> * Update packages/web-components/src/components/combo-button/combo-button.stories.ts Co-authored-by: Ariella Gilmore <[email protected]> * Update packages/web-components/src/components/combo-button/combo-button.stories.ts Co-authored-by: Ariella Gilmore <[email protected]> * Update packages/web-components/src/components/combo-button/combo-button.stories.ts Co-authored-by: Ariella Gilmore <[email protected]> * Update packages/web-components/src/components/combo-button/combo-button.ts Co-authored-by: Ariella Gilmore <[email protected]> * fix(combo-button): click on the menu-item * feat(combo-button): add tooltipContent prop --------- Co-authored-by: Ariella Gilmore <[email protected]>
1 parent 40385e7 commit 4215ae3

File tree

7 files changed

+562
-0
lines changed

7 files changed

+562
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { ArgTypes, Canvas, Markdown, Meta } from '@storybook/blocks';
2+
import { cdnJs } from '../../globals/internal/storybook-cdn';
3+
import * as ComboButtonStories from './combo-button.stories';
4+
5+
<Meta of={ComboButtonStories} />
6+
7+
# ComboButton
8+
9+
[Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/web-components/src/components/combo-button)
10+
11+
## Table of Contents
12+
13+
- [Overview](#overview)
14+
- [With Danger](#with-danger)
15+
- [With Icons](#with-icons)
16+
- [Menu Alignment](#menu-alignment)
17+
- [Experimental Auto Align](#experimental-auto-align)
18+
- [Component API](#component-api)
19+
- [CDN](#cdn)
20+
- [Feedback](#feedback)
21+
22+
## Overview
23+
24+
A `cds-menu-button` can be used to offer additional, secondary actions in a disclosed list next to the primary action. These additional actions must be `cds-menu-item` passed as `children`. The primary action's label is passed as `label`.
25+
26+
```html
27+
<cds-combo-button label="Primary action">
28+
<cds-menu>
29+
<cds-menu-item label="Second action"></cds-menu-item>
30+
<cds-menu-item label="Third action"></cds-menu-item>
31+
<cds-menu-item label="Fourth action"></cds-menu-item>
32+
</cds-menu>
33+
</cds-combo-button>
34+
```
35+
36+
<Canvas
37+
of={ComboButtonStories.Default}
38+
/>
39+
40+
## With Icons
41+
42+
<Canvas of={ComboButtonStories.withIcons} />
43+
44+
## With Danger
45+
46+
<Canvas of={ComboButtonStories.withDanger} />
47+
48+
## Menu Alignment (experimental)
49+
50+
The `menu-alignment` attribute enables you to define the placement of the Menu in
51+
relation to the `cds-menu-button`. For instance, setting `menu-alignment="top"` on
52+
the `cds-menu-button` will render the Menu above the button.
53+
54+
If it seems your specified `menu-alignment` isn't working, it's because we
55+
prioritize ensuring the Menu remains visible. We calculate the optimal position
56+
to display the Menu in case the provided `menu-alignment` obscures it.
57+
58+
We encourage you to play around in the Storybook Default stories to better
59+
understand the `menu-alignment` attribute.
60+
61+
<Canvas of={ComboButtonStories.withMenuAlignment} />
62+
63+
## Experimental Auto Align
64+
65+
<Canvas of={ComboButtonStories.ExperimentalAutoAlign} />
66+
67+
## Component API
68+
69+
<ArgTypes of="cds-combo-button" />
70+
<Markdown>{`${cdnJs({ components: ['combo-button'] })}`}</Markdown>
71+
72+
## Feedback
73+
74+
Help us improve this component by providing feedback, asking questions on Slack,
75+
or updating this file on
76+
[GitHub](https://github.com/carbon-design-system/carbon/edit/main/packages/web-components/src/components/combo-button/combo-button.mdx).
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// Copyright IBM Corp. 2025, 2025
3+
//
4+
// This source code is licensed under the Apache-2.0 license found in the
5+
// LICENSE file in the root directory of this source tree.
6+
//
7+
8+
$css--plex: true !default;
9+
@use '@carbon/styles/scss/config' as *;
10+
@use '@carbon/styles/scss/motion' as *;
11+
@use '@carbon/styles/scss/components/combo-button/index' as *;
12+
13+
:host(#{$prefix}-combo-button) {
14+
@extend .#{$prefix}--combo-button__container;
15+
}
16+
:host(#{$prefix}-combo-button)[_open] #{$prefix}-icon-button svg {
17+
transform: rotate(180deg);
18+
}
19+
20+
:host(#{$prefix}-combo-button) #{$prefix}-icon-button svg {
21+
transition: transform $duration-fast-02 motion(standard, productive);
22+
}
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/**
2+
* Copyright IBM Corp. 2025, 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { html } from 'lit';
9+
import './index';
10+
import CopyFile16 from '@carbon/icons/lib/copy--file/16';
11+
import Export16 from '@carbon/icons/lib/export/16';
12+
13+
const args = {
14+
label: 'Primary action',
15+
size: 'lg',
16+
menuAlignment: 'bottom',
17+
};
18+
19+
const argTypes = {
20+
disabled: {
21+
control: 'boolean',
22+
description: 'Specify whether the ComboButton should be disabled, or not.',
23+
},
24+
label: {
25+
control: 'text',
26+
description: 'Provide the label to be rendered on the trigger button.',
27+
},
28+
menuAlignment: {
29+
control: 'select',
30+
description:
31+
'Experimental property. Specify how the menu should align with the button element',
32+
options: [
33+
'top',
34+
'top-start',
35+
'top-end',
36+
'bottom',
37+
'bottom-start',
38+
'bottom-end',
39+
],
40+
},
41+
onClick: {
42+
control: true,
43+
description:
44+
'Provide an optional function to be called when the primary action element is clicked.',
45+
},
46+
size: {
47+
control: 'radio',
48+
description: `Specify the size of the button and menu.
49+
'sm'
50+
'md'
51+
'lg'`,
52+
options: ['sm', 'md', 'lg'],
53+
},
54+
tooltipAlignment: {
55+
control: 'radio',
56+
description: 'Specify how the trigger tooltip should be aligned.',
57+
},
58+
};
59+
60+
export const Default = {
61+
argTypes: argTypes,
62+
args: args,
63+
render: ({
64+
disabled,
65+
label,
66+
menuAlignment,
67+
size,
68+
tooltipAlignment,
69+
onClick,
70+
}) => html`
71+
<cds-combo-button
72+
label="${label}"
73+
menu-alignment=${menuAlignment}
74+
size=${size}
75+
?disabled=${disabled}
76+
.tooltip-alignment="${tooltipAlignment}"
77+
.onClick=${onClick}>
78+
<cds-menu>
79+
<cds-menu-item
80+
label="Second action with a long label description"></cds-menu-item>
81+
<cds-menu-item label="Third action"></cds-menu-item>
82+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
83+
<cds-menu-item-divider></cds-menu-item-divider>
84+
<cds-menu-item label="Danger action" kind="danger"></cds-menu-item>
85+
</cds-menu>
86+
</cds-combo-button>
87+
`,
88+
};
89+
90+
export const ExperimentalAutoAlign = {
91+
argTypes: argTypes,
92+
args: args,
93+
render: ({
94+
disabled,
95+
label,
96+
menuAlignment,
97+
size,
98+
tooltipAlignment,
99+
onClick,
100+
}) => html`
101+
<div style="width: 5000px; height: 5000px;">
102+
<div style="position: absolute; bottom: 20px">
103+
<cds-combo-button
104+
label="${label}"
105+
menu-alignment=${menuAlignment}
106+
size=${size}
107+
?disabled=${disabled}
108+
.tooltip-alignment="${tooltipAlignment}">
109+
<cds-menu>
110+
<cds-menu-item
111+
label="Second action with a long label description"></cds-menu-item>
112+
<cds-menu-item label="Third action"></cds-menu-item>
113+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
114+
</cds-menu>
115+
</cds-combo-button>
116+
</div>
117+
</div>
118+
`,
119+
};
120+
121+
export const withDanger = {
122+
argTypes: argTypes,
123+
args: args,
124+
render: ({ disabled, label, menuAlignment, size, tooltipAlignment }) => html`
125+
<cds-combo-button
126+
label="${label}"
127+
menu-alignment=${menuAlignment}
128+
size=${size}
129+
?disabled=${disabled}
130+
.tooltip-alignment="${tooltipAlignment}">
131+
<cds-menu>
132+
<cds-menu-item
133+
label="Second action with a long label description"></cds-menu-item>
134+
<cds-menu-item label="Third action"></cds-menu-item>
135+
<cds-menu-item label="Fourth action"></cds-menu-item>
136+
<cds-menu-item-divider></cds-menu-item-divider>
137+
<cds-menu-item label="Danger action" kind="danger"></cds-menu-item>
138+
</cds-menu>
139+
</cds-combo-button>
140+
`,
141+
};
142+
143+
export const withIcons = {
144+
argTypes: argTypes,
145+
args: {
146+
label: 'Save record',
147+
size: 'lg',
148+
menuAlignment: 'bottom',
149+
},
150+
render: ({ disabled, label, menuAlignment, size, tooltipAlignment }) => html`
151+
<cds-combo-button
152+
label="${label}"
153+
menu-alignment=${menuAlignment}
154+
size=${size}
155+
?disabled=${disabled}
156+
.tooltip-alignment="${tooltipAlignment}">
157+
<cds-menu>
158+
<cds-menu-item label="Save as a copy">
159+
${CopyFile16({ slot: 'render-icon' })}
160+
</cds-menu-item>
161+
<cds-menu-item label="Export">
162+
${Export16({ slot: 'render-icon' })}
163+
</cds-menu-item>
164+
</cds-menu>
165+
</cds-combo-button>
166+
</div>
167+
`,
168+
};
169+
170+
export const withMenuAlignment = {
171+
render: () => html`
172+
<div style="display: flex; justify-content: space-between;">
173+
<cds-combo-button label="Bottom" menu-alignment="bottom">
174+
<cds-menu>
175+
<cds-menu-item
176+
label="Second action with a long label description"></cds-menu-item>
177+
<cds-menu-item label="Third action"></cds-menu-item>
178+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
179+
</cds-menu>
180+
</cds-combo-button>
181+
182+
<cds-combo-button label="Bottom start" menu-alignment="bottom-start">
183+
<cds-menu>
184+
<cds-menu-item
185+
label="Second action with a long label description"></cds-menu-item>
186+
<cds-menu-item label="Third action"></cds-menu-item>
187+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
188+
</cds-menu>
189+
</cds-combo-button>
190+
191+
<cds-combo-button label="Bottom end" menu-alignment="bottom-end">
192+
<cds-menu>
193+
<cds-menu-item
194+
label="Second action with a long label description"></cds-menu-item>
195+
<cds-menu-item label="Third action"></cds-menu-item>
196+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
197+
</cds-menu>
198+
</cds-combo-button>
199+
</div>
200+
201+
<div
202+
style="display: flex; justify-content: space-between; margin-top: 15rem">
203+
<cds-combo-button
204+
label="Top"
205+
menu-alignment="top"
206+
tooltip-alignment="bottom">
207+
<cds-menu>
208+
<cds-menu-item
209+
label="Second action with a long label description"></cds-menu-item>
210+
<cds-menu-item label="Third action"></cds-menu-item>
211+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
212+
</cds-menu>
213+
</cds-combo-button>
214+
215+
<cds-combo-button
216+
label="Top start"
217+
menu-alignment="top-start"
218+
tooltip-alignment="bottom">
219+
<cds-menu>
220+
<cds-menu-item
221+
label="Second action with a long label description"></cds-menu-item>
222+
<cds-menu-item label="Third action"></cds-menu-item>
223+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
224+
</cds-menu>
225+
</cds-combo-button>
226+
227+
<cds-combo-button
228+
label="Top end"
229+
menu-alignment="top-end"
230+
tooltip-alignment="bottom">
231+
<cds-menu>
232+
<cds-menu-item
233+
label="Second action with a long label description"></cds-menu-item>
234+
<cds-menu-item label="Third action"></cds-menu-item>
235+
<cds-menu-item label="Fourth action" disabled></cds-menu-item>
236+
</cds-menu>
237+
</cds-combo-button>
238+
</div>
239+
`,
240+
};
241+
242+
const meta = {
243+
title: 'Components/Combo Button',
244+
};
245+
246+
export default meta;

0 commit comments

Comments
 (0)