From de67bcc9d51d4ea52037777107291ec211f51b21 Mon Sep 17 00:00:00 2001 From: Adrian Flatner Date: Wed, 3 Jun 2026 13:42:52 +0200 Subject: [PATCH 1/3] feat(Suggestion): add count display mode for multiple selection --- .../content/components/suggestion/en/code.mdx | 7 ++ .../content/components/suggestion/no/code.mdx | 7 ++ .../suggestion/suggestion.stories.tsx | 89 +++++++++++++++++++ packages/css/src/suggestion.css | 31 +++++++ .../src/components/suggestion/suggestion.mdx | 2 + .../suggestion/suggestion.stories.tsx | 30 +++++++ .../src/components/suggestion/suggestion.tsx | 16 ++++ 7 files changed, 182 insertions(+) diff --git a/apps/www/app/content/components/suggestion/en/code.mdx b/apps/www/app/content/components/suggestion/en/code.mdx index 32ab2b3852..d84e3a4674 100644 --- a/apps/www/app/content/components/suggestion/en/code.mdx +++ b/apps/www/app/content/components/suggestion/en/code.mdx @@ -61,6 +61,13 @@ To allow users to select multiple options, use `data-multiple` on suggestion. +### Multiple choice with count tag + +Use `data-count` to hide chips and show the number of selected options in the input field. +Customize the tag text with the `--dsc-suggestion-count-label` CSS variable. + + + ### Adding new options With `data-creatable` on suggestion, a user can create new selected options by entering text in the input and pressing Enter. diff --git a/apps/www/app/content/components/suggestion/no/code.mdx b/apps/www/app/content/components/suggestion/no/code.mdx index bd736e3ddc..4e311aa935 100644 --- a/apps/www/app/content/components/suggestion/no/code.mdx +++ b/apps/www/app/content/components/suggestion/no/code.mdx @@ -61,6 +61,13 @@ For å tillate at brukeren kan velge flere alternativer, bruk `data-multiple` p +### Flervalg med tag for å vise antall valgt + +Bruk `data-count` for å skjule chips og vise antall valgte alternativer i inputfeltet. +Tilpass teksten med CSS-variabelen `--dsc-suggestion-count-label`. + + + ### Legge til nye alternativer Med `data-creatable` på suggestion kan en bruker opprette nye valgte alternativer ved å skrive inn tekst i input og trykke Enter. diff --git a/apps/www/app/content/components/suggestion/suggestion.stories.tsx b/apps/www/app/content/components/suggestion/suggestion.stories.tsx index 9644cf1e82..fdeebb1185 100644 --- a/apps/www/app/content/components/suggestion/suggestion.stories.tsx +++ b/apps/www/app/content/components/suggestion/suggestion.stories.tsx @@ -308,6 +308,95 @@ export const Creatable = () => { ); }; +export const MultipleCount = () => { + const DATA_PLACES = [ + 'Sogndal', + 'Oslo', + 'Brønnøysund', + 'Stavanger', + 'Trondheim', + 'Bergen', + 'Lillestrøm', + ]; + const [selected, setSelected] = useState(["Sogndal"]); + + return ( + + + + setSelected(items.map((item) => item.value)) + } + > + + + + + Ingen treff + + {DATA_PLACES.map((place) => ( + + {place} + + ))} + + + + ); +}; + +export const MultipleCountEn = () => { + const DATA_PLACES = [ + 'Sogndal', + 'Oslo', + 'Brønnøysund', + 'Stavanger', + 'Trondheim', + 'Bergen', + 'Lillestrøm', + ]; + const [selected, setSelected] = useState(["Sogndal"]); + + return ( + + + + setSelected(items.map((item) => item.value)) + } + style={{ '--dsc-suggestion-count-label': '"selected"' } as React.CSSProperties} + > + + + + + No results found + + {DATA_PLACES.map((place) => ( + + {place} + + ))} + + + + ); +}; + export const CreatableEn = () => { const DATA_PLACES = [ 'Sogndal', diff --git a/packages/css/src/suggestion.css b/packages/css/src/suggestion.css index 6cb2bc2909..ab4ad346be 100644 --- a/packages/css/src/suggestion.css +++ b/packages/css/src/suggestion.css @@ -62,6 +62,37 @@ display: none; /* Hide data elements when not in multiple mode */ } + /* Count display mode: hide chips, show count label inside input */ + &[data-count] data { + display: none; + } + + /* NOTE: This styling should be reflected in tag.css */ + &[data-count]::before { + content: attr(data-count) ' ' var(--dsc-suggestion-count-label, 'valgt'); + position: absolute; + inset-inline-start: var(--ds-size-3); + top: 50%; + translate: 0 -50%; + pointer-events: none; + z-index: 1; + align-items: center; + background: var(--ds-color-surface-tinted); + border: solid transparent var(--ds-border-width-default); + border-radius: var(--ds-border-radius-sm); + box-sizing: border-box; + color: var(--ds-color-text-default); + font-size: var(--ds-body-sm-font-size); + line-height: var(--ds-line-height-sm); + min-height: var(--ds-size-8); + padding: 0 var(--ds-size-2); + display: inline-flex; + } + + &[data-count]:focus-within::before { + display: none; + } + /* NOTE: This styling should be reflected in chip.css */ & > data { align-items: center; diff --git a/packages/react/src/components/suggestion/suggestion.mdx b/packages/react/src/components/suggestion/suggestion.mdx index 50203adf17..949c89b847 100644 --- a/packages/react/src/components/suggestion/suggestion.mdx +++ b/packages/react/src/components/suggestion/suggestion.mdx @@ -10,6 +10,8 @@ import * as SuggestionStories from './suggestion.stories'; + + diff --git a/packages/react/src/components/suggestion/suggestion.stories.tsx b/packages/react/src/components/suggestion/suggestion.stories.tsx index 2cc45bcd63..f606b6b309 100644 --- a/packages/react/src/components/suggestion/suggestion.stories.tsx +++ b/packages/react/src/components/suggestion/suggestion.stories.tsx @@ -507,6 +507,36 @@ Multiple.args = { multiple: true, }; +export const MultipleCount: StoryFn = (args) => { + const [selected, setSelected] = useState(["Sogndal"]); + + return ( + + + + setSelected(items.map((item) => item.value)) + } + > + + + + Tomt + {DATA_PLACES.map((place) => ( + + {place} + + ))} + + + + ); +}; + export const InDetails: StoryFn = (args) => { return (
diff --git a/packages/react/src/components/suggestion/suggestion.tsx b/packages/react/src/components/suggestion/suggestion.tsx index cf78ba4fe2..78e427f9dc 100644 --- a/packages/react/src/components/suggestion/suggestion.tsx +++ b/packages/react/src/components/suggestion/suggestion.tsx @@ -92,6 +92,17 @@ type SuggestionBaseProps = { * @default ({ label }) => label */ renderSelected?: (args: { label: string; value: string }) => ReactNode; + /** + * How selected items are displayed when `multiple` is true. + * + * - `chips` renders removable chips for each selected item (default) + * - `count` hides chips and shows a count label (e.g. "2 valgt") + * + * Customize the label text with the `--dsc-suggestion-count-label` CSS variable. + * + * @default 'chips' + */ + display?: 'chips' | 'count'; } & Omit, 'defaultValue'>; type SuggestionValueProps = { @@ -169,6 +180,7 @@ export const Suggestion = forwardRef( className, creatable = false, defaultSelected, + display = 'chips', filter = true, multiple = false, name, @@ -266,6 +278,10 @@ export const Suggestion = forwardRef( adds attributes From b4d5dfaf19152e6d7661d9ef50c0b08da0c51525 Mon Sep 17 00:00:00 2001 From: Adrian Flatner Date: Thu, 4 Jun 2026 11:41:53 +0200 Subject: [PATCH 2/3] add changeset --- .changeset/bright-goats-cry.md | 5 +++++ .changeset/great-jeans-follow.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/bright-goats-cry.md create mode 100644 .changeset/great-jeans-follow.md diff --git a/.changeset/bright-goats-cry.md b/.changeset/bright-goats-cry.md new file mode 100644 index 0000000000..6d25add601 --- /dev/null +++ b/.changeset/bright-goats-cry.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": minor +--- + +Suggestion: Added `display` prop for multiple Suggestion. Set `display="count"` on a multiple Suggestion to show a count label instead of chips. diff --git a/.changeset/great-jeans-follow.md b/.changeset/great-jeans-follow.md new file mode 100644 index 0000000000..dbfc791bf7 --- /dev/null +++ b/.changeset/great-jeans-follow.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": minor +--- + +Suggestion: Added count display mode for multiple Suggestion. Use `data-count` to hide chips and show a count label inside the input. Customize the label text with `--dsc-suggestion-count-label`. From 1aeaf16ca2246b2657d191f958a46299a2ee93ba Mon Sep 17 00:00:00 2001 From: Adrian Flatner Date: Thu, 4 Jun 2026 12:01:19 +0200 Subject: [PATCH 3/3] biome format --- .../suggestion/suggestion.stories.tsx | 10 ++-- .../suggestion/suggestion.stories.tsx | 48 +++++++++---------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/apps/www/app/content/components/suggestion/suggestion.stories.tsx b/apps/www/app/content/components/suggestion/suggestion.stories.tsx index fdeebb1185..f4fdd19b29 100644 --- a/apps/www/app/content/components/suggestion/suggestion.stories.tsx +++ b/apps/www/app/content/components/suggestion/suggestion.stories.tsx @@ -318,7 +318,7 @@ export const MultipleCount = () => { 'Bergen', 'Lillestrøm', ]; - const [selected, setSelected] = useState(["Sogndal"]); + const [selected, setSelected] = useState(['Sogndal']); return ( @@ -362,7 +362,7 @@ export const MultipleCountEn = () => { 'Bergen', 'Lillestrøm', ]; - const [selected, setSelected] = useState(["Sogndal"]); + const [selected, setSelected] = useState(['Sogndal']); return ( @@ -374,7 +374,11 @@ export const MultipleCountEn = () => { onSelectedChange={(items) => setSelected(items.map((item) => item.value)) } - style={{ '--dsc-suggestion-count-label': '"selected"' } as React.CSSProperties} + style={ + { + '--dsc-suggestion-count-label': '"selected"', + } as React.CSSProperties + } > diff --git a/packages/react/src/components/suggestion/suggestion.stories.tsx b/packages/react/src/components/suggestion/suggestion.stories.tsx index f606b6b309..1d2ef28715 100644 --- a/packages/react/src/components/suggestion/suggestion.stories.tsx +++ b/packages/react/src/components/suggestion/suggestion.stories.tsx @@ -508,32 +508,32 @@ Multiple.args = { }; export const MultipleCount: StoryFn = (args) => { - const [selected, setSelected] = useState(["Sogndal"]); + const [selected, setSelected] = useState(['Sogndal']); return ( - - - - setSelected(items.map((item) => item.value)) - } - > - - - - Tomt - {DATA_PLACES.map((place) => ( - - {place} - - ))} - - - + + + + setSelected(items.map((item) => item.value)) + } + > + + + + Tomt + {DATA_PLACES.map((place) => ( + + {place} + + ))} + + + ); };