WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8b32417
fix: padding on non-interactiveGroup parent
SpyZzey Nov 27, 2025
bd8ccd4
fix: remove disableContentStyling=true
SpyZzey Nov 27, 2025
009c20f
test: move disable-content-styling prop to custom permutations page
SpyZzey Dec 4, 2025
5787ba6
fix: rename disable-content-styling.permutations.tsx to include .page
SpyZzey Dec 4, 2025
e6a2eed
fix: disabled color set when no-content-styling enabled
SpyZzey Nov 27, 2025
03b7782
feat: add renderOption api to autosuggest
SpyZzey Nov 25, 2025
229b725
feat: add renderOption api to select and multiselect
SpyZzey Nov 25, 2025
23a5add
feat: arbitrary content for select, multiselect
SpyZzey Nov 27, 2025
b3998da
Revert "feat: add renderOption api to autosuggest"
SpyZzey Nov 27, 2025
c7c1121
chore: remove two examples in pages
SpyZzey Nov 27, 2025
7d87fa4
feat: improve api
SpyZzey Nov 27, 2025
684ae6d
test: update snapshots
SpyZzey Nov 27, 2025
b162961
revert: checkbox style class
SpyZzey Nov 27, 2025
b94eea9
test: add support for test-utils, add data-test-indices to multiselec…
SpyZzey Nov 28, 2025
17c5a3e
test: add tests for select + multiselect renderOption
SpyZzey Nov 28, 2025
bf43628
fix: workaround for documenter bug
SpyZzey Dec 1, 2025
712e632
refactor: move renderOption-content to Option-component
SpyZzey Dec 4, 2025
9d48d6f
chore: update snapshots
SpyZzey Dec 4, 2025
97f806b
refactor: restructure BaseSelectItem and BaseMultiselectItem
SpyZzey Dec 8, 2025
2365b78
fix: update snapshots
SpyZzey Dec 8, 2025
85ad376
fix: add null as return value for findCustomContent
SpyZzey Dec 8, 2025
85a8650
feat: change child/parent to item/group in multiselect/select
SpyZzey Dec 8, 2025
83a5b34
test: option displays custom content
SpyZzey Dec 8, 2025
8c1ad75
test: add findLabel in displays custom content test
SpyZzey Dec 8, 2025
c7f456e
test: remove options from multiselect+select custom render option test
SpyZzey Dec 8, 2025
65a7175
chore: remove test-indices
SpyZzey Dec 8, 2025
6d4d323
chore: remove comment only related to core-only feature
SpyZzey Dec 8, 2025
c57ce94
feat: add custom trigger option for select, refactor: simplify select…
SpyZzey Dec 8, 2025
e90f788
fix: unknown property
SpyZzey Dec 8, 2025
265e49e
chore: update snapshots
SpyZzey Dec 8, 2025
ab921af
test: renderOption in trigger
SpyZzey Dec 8, 2025
4d93dfb
fix: make index mandatory
SpyZzey Dec 9, 2025
af7a8af
refactor: remove uncessary tags in unit test
SpyZzey Dec 9, 2025
93d529f
refactor: add line breaks
SpyZzey Dec 9, 2025
cab5c0f
fix: set disableContentStyling incorrectly
SpyZzey Dec 9, 2025
6435be5
feat: add parent property to select option item
SpyZzey Dec 11, 2025
f79ea25
feat: use SimplePage instead of ScreenshotArea
SpyZzey Dec 12, 2025
39a4e91
chore: update snapshots
SpyZzey Dec 15, 2025
84702f9
chore: change width to inlineSize
SpyZzey Dec 15, 2025
b23285d
chore: change snapshot deprecated goo.gl to long url
SpyZzey Dec 15, 2025
556f3fd
test: remove the findCustomContent testutil
SpyZzey Dec 17, 2025
9ab75e2
test: Add test for parent attribute in select + multiselect
SpyZzey Dec 18, 2025
efa8686
refactor: Rename variables in render-option tests
SpyZzey Dec 18, 2025
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
2 changes: 1 addition & 1 deletion pages/dropdown/list-with-sticky-item.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default function MultiselectPage() {
>
<ListComponent
menuProps={{ statusType: 'finished', ref, open }}
getOptionProps={(option, index) => ({ option: { ...option }, key: index, open })}
getOptionProps={(option, index) => ({ option: { ...option }, key: index, index: index, open })}
filteredOptions={options}
filteringValue={''}
firstOptionSticky={true}
Expand Down
67 changes: 67 additions & 0 deletions pages/multiselect/custom-render-option.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';

import { Multiselect, MultiselectProps } from '~components';
import { SelectProps } from '~components/select';

import { SimplePage } from '../app/templates';
import { i18nStrings } from './constants';
const lotsOfOptions: SelectProps.Options = [...Array(50)].map((_, index) => ({
value: `Option ${index}`,
label: `Option ${index}`,
}));
const options: SelectProps.Options = [
{ value: 'first', label: 'Simple' },
{ value: 'second', label: 'With small icon', iconName: 'folder' },
{
value: 'third',
label: 'With big icon icon',
description: 'Very big option',
iconName: 'heart',
disabled: false,
disabledReason: 'disabled reason',
tags: ['Cool', 'Intelligent', 'Cat'],
},
{
label: 'Option group',
options: [{ value: 'forth', label: 'Nested option' }],
disabledReason: 'disabled reason',
},
...lotsOfOptions,
{ label: 'Last option', disabled: false, disabledReason: 'disabled reason' },
];

export default function SelectPage() {
const [selectedOptions, setSelectedOptions] = React.useState<MultiselectProps.Options>([]);
const renderOptionItem: MultiselectProps.MultiselectOptionItemRenderer = ({ item }) => {
if (item.type === 'select-all') {
return <div>Select all? {item.selected ? 'Yes' : 'No'}</div>;
} else if (item.type === 'group') {
return <div>Group: {item.option.label}</div>;
} else if (item.type === 'item') {
return <div>Item: {item.option.label}</div>;
}

return null;
};

return (
<SimplePage title="Multiselect with custom item renderer" screenshotArea={{}}>
<div style={{ inlineSize: '400px' }}>
<Multiselect
enableSelectAll={true}
i18nStrings={{ ...i18nStrings, selectAllText: 'Select all' }}
filteringType={'auto'}
renderOption={renderOptionItem}
placeholder="Choose option"
selectedOptions={selectedOptions}
onChange={event => {
setSelectedOptions(event.detail.selectedOptions);
}}
options={options}
/>
</div>
</SimplePage>
);
}
67 changes: 67 additions & 0 deletions pages/select/custom-render-option.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { useState } from 'react';

import Select, { SelectProps } from '~components/select';

import { SimplePage } from '../app/templates';

const lotsOfOptions = [...Array(50).keys()].map(n => {
const numberToDisplay = (n + 5).toString();
return {
value: numberToDisplay,
label: `Option ${n + 5}`,
};
});

const options: SelectProps.Options = [
{ value: 'first', label: 'Simple' },
{ value: 'second', label: 'With small icon', iconName: 'folder' },
{
value: 'third',
label: 'With big icon icon',
description: 'Very big option',
iconName: 'heart',
disabled: true,
disabledReason: 'disabled reason',
tags: ['Cool', 'Intelligent', 'Cat'],
},
{
label: 'Option group',
options: [{ value: 'forth', label: 'Nested option' }],
disabledReason: 'disabled reason',
},
...lotsOfOptions,
{ label: 'Last option', disabled: true, disabledReason: 'disabled reason' },
];

export default function SelectPage() {
const [selectedOption, setSelectedOption] = useState<SelectProps.Option | null>(null);
const renderOption: SelectProps.SelectOptionItemRenderer = ({ item }) => {
if (item.type === 'trigger') {
return <div>Trigger: {item.option.label}</div>;
} else if (item.type === 'group') {
return <div>Group: {item.option.label}</div>;
} else if (item.type === 'item') {
return <div>Item: {item.option.label}</div>;
}
return null;
};

return (
<SimplePage title="Select with custom item renderer" screenshotArea={{}}>
<div style={{ inlineSize: '400px' }}>
<Select
filteringType="auto"
renderOption={renderOption}
placeholder="Choose option"
selectedOption={selectedOption}
onChange={({ detail }) => setSelectedOption(detail.selectedOption)}
options={options}
triggerVariant="option"
/>
</div>
</SimplePage>
);
}
7 changes: 5 additions & 2 deletions pages/select/item.permutations.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const options: Record<string, DropdownOption> = {
},
};

const permutations = createPermutations<ItemProps>([
const permutations = createPermutations<Omit<ItemProps, 'index'>>([
{
option: [options.simpleOption],
highlighted: [false, true],
Expand Down Expand Up @@ -150,7 +150,10 @@ export default function InputPermutations() {
<h1>Select item permutations</h1>
<ScreenshotArea>
<ul role="listbox" aria-label="list">
<PermutationsView permutations={permutations} render={permutation => <Item {...permutation} />} />
<PermutationsView
permutations={permutations}
render={(permutation, index) => <Item index={index ?? -1} {...permutation} />}
/>
</ul>
</ScreenshotArea>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`Components definition for alert matches the snapshot: alert 1`] = `
{
Expand Down Expand Up @@ -17791,6 +17791,26 @@ For more information, see the
"optional": true,
"type": "SelectProps.ContainingOptionAndGroupString",
},
{
"description": "Specifies a render function to render custom options in the dropdown menu.",
"inlineType": {
"name": "MultiselectProps.MultiselectOptionItemRenderer",
"parameters": [
{
"name": "props",
"type": "{ item: MultiselectProps.MultiselectItem; filterText?: string | undefined; }",
},
],
"returnType": "React.ReactNode",
"type": "function",
},
"name": "renderOption",
"optional": true,
"systemTags": [
"core",
],
"type": "MultiselectProps.MultiselectOptionItemRenderer",
},
{
"description": "Specifies the localized string that describes an option as being selected.
This is required to provide a good screen reader experience. For more information, see the
Expand Down Expand Up @@ -23336,6 +23356,26 @@ For more information, see the
"optional": true,
"type": "SelectProps.ContainingOptionAndGroupString",
},
{
"description": "Specifies a render function to render custom options in the dropdown menu or trigger.",
"inlineType": {
"name": "SelectProps.SelectOptionItemRenderer",
"parameters": [
{
"name": "props",
"type": "{ item: SelectProps.SelectItem; filterText?: string | undefined; }",
},
],
"returnType": "React.ReactNode",
"type": "function",
},
"name": "renderOption",
"optional": true,
"systemTags": [
"core",
],
"type": "SelectProps.SelectOptionItemRenderer",
},
{
"description": "Specifies the localized string that describes an option as being selected.
This is required to provide a good screen reader experience. For more information, see the
Expand Down Expand Up @@ -32389,6 +32429,7 @@ Options get highlighted when they match the value of the input field.",
},
},
{
"description": "Finds the label wrapper of this option.",
"name": "findLabel",
"parameters": [],
"returnType": {
Expand Down Expand Up @@ -43409,6 +43450,7 @@ Options get highlighted when they match the value of the input field.",
},
},
{
"description": "Finds the label wrapper of this option.",
"name": "findLabel",
"parameters": [],
"returnType": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ exports[`test-utils selectors 1`] = `
"awsui_chart-filter_1px7g",
"awsui_content_x6dl3",
"awsui_control_1wepg",
"awsui_custom-content_1p2cx",
"awsui_description_1p2cx",
"awsui_description_1wepg",
"awsui_direction-button-block-end_8k1rt",
Expand Down
5 changes: 4 additions & 1 deletion src/internal/components/button-trigger/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface ButtonTriggerProps extends BaseComponentProps {
onClick?: CancelableEventHandler;
onFocus?: CancelableEventHandler;
onBlur?: CancelableEventHandler<{ relatedTarget: Node | null }>;
hasCustomContent?: boolean;
autoFocus?: boolean;
}

Expand All @@ -62,6 +63,7 @@ const ButtonTrigger = (
onClick,
onFocus,
onBlur,
hasCustomContent = false,
autoFocus,
...restProps
}: ButtonTriggerProps,
Expand All @@ -83,7 +85,8 @@ const ButtonTrigger = (
readOnly && styles.readonly,
inFilteringToken && styles['in-filtering-token'],
inFilteringToken && styles[`in-filtering-token-${inFilteringToken}`],
inlineTokens && styles['inline-tokens']
inlineTokens && styles['inline-tokens'],
!!hasCustomContent && styles['custom-option']
),
disabled: disabled,
'aria-expanded': pressed,
Expand Down
7 changes: 7 additions & 0 deletions src/internal/components/button-trigger/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ $padding-block-inner-filtering-token: 0px;
}
}

&.custom-option {
// Remove default paddings for custom options
padding-block: 0;
padding-inline-start: 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No padding-inline-end?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, setting the padding-inline-end to 0 causes the select chevron to overlap the trigger content, so I'd just leave it as is.

overflow: clip;
}

&.inline-tokens {
// Remove default paddings and just rely on center alignment of the content
padding-block: 0;
Expand Down
11 changes: 11 additions & 0 deletions src/internal/components/option/__tests__/option.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ describe('Option component', () => {
value: 'optionABC',
label: 'ABC',
};
test('displays custom content', () => {
const optionWrapper = renderOption({
customContent: <div>My Custom Content</div>,
option: {
...baseOption,
},
});
expect(optionWrapper.findLabel()!.getElement()).toHaveTextContent('My Custom Content');
expect(optionWrapper!.getElement()).toHaveTextContent('My Custom Content');
});

test('displays label', () => {
const optionWrapper = renderOption({
option: baseOption,
Expand Down
10 changes: 9 additions & 1 deletion src/internal/components/option/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,20 @@ const Option = ({
labelContainerRef,
labelRef,
labelId,
customContent,
...restProps
}: OptionProps) => {
if (!option) {
return null;
}
if (customContent) {
return (
<div data-value={option.value} className={clsx(styles.option)}>
<div className={clsx(styles['custom-content'])}>{customContent}</div>
</div>
);
}

const { disabled } = option;
const baseProps = getBaseProps(restProps);
const SpanOrDivTag = option.labelContent ? 'div' : 'span';
Expand All @@ -55,7 +64,6 @@ const Option = ({
validateStringValue(tag, `filteringTags[${index}]`);
});
}

const className = clsx(
styles.option,
disabled && styles.disabled,
Expand Down
3 changes: 2 additions & 1 deletion src/internal/components/option/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import React, { ReactNode } from 'react';

import { IconProps } from '../../../icon/interfaces';
import { BaseComponentProps } from '../../base-component';
Expand Down Expand Up @@ -54,4 +54,5 @@ export interface OptionProps extends BaseComponentProps {
labelContainerRef?: React.RefObject<HTMLSpanElement>;
labelRef?: React.RefObject<HTMLSpanElement>;
labelId?: string;
customContent?: ReactNode;
}
4 changes: 4 additions & 0 deletions src/internal/components/option/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,7 @@
.trigger-variant {
@include styles.text-overflow-ellipsis;
}

.custom-content {
inline-size: 100%;
}
1 change: 1 addition & 0 deletions src/internal/components/selectable-item/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
}
}
}

&.highlighted {
z-index: 3;
background-color: awsui.$color-background-dropdown-item-hover;
Expand Down
Loading
Loading