diff --git a/packages/react/src/components/Checkbox/Checkbox.stories.mdx b/packages/react/src/components/Checkbox/Checkbox.stories.mdx index 4d8c4b1580..9f10119fd4 100644 --- a/packages/react/src/components/Checkbox/Checkbox.stories.mdx +++ b/packages/react/src/components/Checkbox/Checkbox.stories.mdx @@ -41,6 +41,9 @@ import {ArgsTable} from "@storybook/addon-docs"; description: 'Gir sjekkboksen en rød ramme for å indikere en feil.', control: {type: 'boolean'} }, + helpText: { + description: 'Legger på en hjelpe-tekst knapp ved siden av labelen til checkboxen.', + }, hideLabel: { description: 'Skjuler teksten til høyre for sjekkboksen, men gjør den tilgjengelig for verktøy som skjermlesere.', control: {type: 'boolean'} @@ -100,6 +103,15 @@ Sjekkboksene kan ha flere forskjellige statuser: > {Template.bind({})} + + {Template.bind({})} + +### Med hjelpetekst + + + {Template.bind({})} + + + ### Deaktivert & Required>; @@ -28,6 +28,7 @@ export interface CheckboxGroupProps { description?: ReactNode; disabled?: boolean; error?: ReactNode; + helpText?: string; items: CheckboxGroupItem[]; legend?: ReactNode; onChange?: (names: CheckedNames) => void; @@ -57,6 +58,7 @@ export const CheckboxGroup = ({ description, disabled, error, + helpText, items, legend, onChange, @@ -93,6 +95,7 @@ export const CheckboxGroup = ({ description={description} disabled={disabled} error={error} + helpText={helpText} legend={legend} size={compact ? FieldSetSize.Xsmall : FieldSetSize.Small} > @@ -104,6 +107,7 @@ export const CheckboxGroup = ({ description={item.description} disabled={disabled || item.disabled} error={!!error} + helpText={item.helpText} key={item.name} label={item.label} name={item.name} diff --git a/packages/react/src/components/FieldSet/FieldSet.module.css b/packages/react/src/components/FieldSet/FieldSet.module.css index 2534466939..561d444838 100644 --- a/packages/react/src/components/FieldSet/FieldSet.module.css +++ b/packages/react/src/components/FieldSet/FieldSet.module.css @@ -4,6 +4,7 @@ --description-color: var(--component-field_description-color-text-default); --description-margin_top: var(--component-field_description-space-top-small); --error_message-margin_top: var(--component-fieldset-space-gap-y-small); + --help_text-gap: var(--component-field_description-space-top-small); --font_size: var(--component-checkbox-font_size-sm); color: var(--color); @@ -18,6 +19,7 @@ --content-margin_top: var(--component-fieldset-space-gap-y-xsmall); --description-margin_top: var(--component-field_description-space-top-xsmall); --error_message-margin_top: var(--component-fieldset-space-gap-y-xsmall); + --help_text-gap: var(--component-field_description-space-top-xsmall); --font_size: var(--component-checkbox-font_size-xs); } @@ -29,11 +31,20 @@ opacity: 1; } +.legendAndHelpText { + display: flex; + gap: var(--help_text-gap); + padding: 0; +} + .legend { - font-weight: bold; padding: 0; } +.legendContent { + font-weight: bold; +} + .description { color: var(--description-color); margin: 0; diff --git a/packages/react/src/components/FieldSet/FieldSet.stories.mdx b/packages/react/src/components/FieldSet/FieldSet.stories.mdx index 15e81db225..fbe0ca7fde 100644 --- a/packages/react/src/components/FieldSet/FieldSet.stories.mdx +++ b/packages/react/src/components/FieldSet/FieldSet.stories.mdx @@ -31,7 +31,8 @@ export const Template = (args) =>
{args.children}
children:

Her er det noe innhold.

, legend: 'Dette er en tittel', description: 'Dette er en beskrivelse av innholdet.', - size: FieldSetSize.Small + size: FieldSetSize.Small, + helpText: 'Help', }} > {Template.bind({})} @@ -41,8 +42,10 @@ export const Template = (args) =>
{args.children}
## Egenskaper Det er mulig å legge til en tittel (`legend`) og en beskrivelse (`description`). -Man kan også vise en feilmelding relatert til gruppen ved å bruke `error`-attributten. -Setter man `disabled` til `true`, vil alle feltene i gruppen bli deaktivert. +Man kan legge til en hjelpetekst som vises ved aktivering av hjelpetekst-knappen +ved å bruke `helpText`-attributten. Man kan også vise en feilmelding relatert til +gruppen ved å bruke `error`-attributten. Setter man `disabled` til `true`, vil alle +feltene i gruppen bli deaktivert. diff --git a/packages/react/src/components/FieldSet/FieldSet.tsx b/packages/react/src/components/FieldSet/FieldSet.tsx index 2f3b14e518..64bf34e026 100644 --- a/packages/react/src/components/FieldSet/FieldSet.tsx +++ b/packages/react/src/components/FieldSet/FieldSet.tsx @@ -1,7 +1,9 @@ -import React, { ReactNode } from 'react'; +import type { ReactNode } from 'react'; +import React from 'react'; import cn from 'classnames'; -import { ErrorMessage } from '../'; +import { ErrorMessage, HelpText } from '../'; +import { HelpTextSize } from '../HelpText/HelpText'; import classes from './FieldSet.module.css'; @@ -12,6 +14,7 @@ export interface FieldSetProps { description?: ReactNode; disabled?: boolean; error?: ReactNode; + helpText?: string; legend?: ReactNode; size?: FieldSetSize; } @@ -28,20 +31,39 @@ export const FieldSet = ({ description, disabled, error, + helpText, legend, size = FieldSetSize.Small, -}: FieldSetProps) => ( -
- {legend && {legend}} - {description &&

{description}

} -
{children}
- {error && ( -
- {error} -
- )} -
-); +}: FieldSetProps) => { + const helpTextSize = + size === FieldSetSize.Xsmall ? HelpTextSize.Xsmall : HelpTextSize.Small; + return ( +
+ {legend && ( + + + {legend} + {helpText && ( + + {helpText} + + )} + + + )} + {description &&

{description}

} +
{children}
+ {error && ( +
+ {error} +
+ )} +
+ ); +}; diff --git a/packages/react/src/components/HelpText/HelpText.module.css b/packages/react/src/components/HelpText/HelpText.module.css index 454f6a8024..1446701198 100644 --- a/packages/react/src/components/HelpText/HelpText.module.css +++ b/packages/react/src/components/HelpText/HelpText.module.css @@ -33,11 +33,21 @@ .helpTextIcon { color: var(--colors-blue-700); - width: 24px; - height: 24px; + width: var(--help_text-icon-width); + height: var(--help_text-icon-height); } .helpTextContent { font-size: var(--font_size-300); line-height: var(--typography-default-line-height); } + +.helpTextIcon.small { + --help_text-icon-width: 24px; + --help_text-icon-height: 24px; +} + +.helpTextIcon.xsmall { + --help_text-icon-width: 18px; + --help_text-icon-height: 18px; +} diff --git a/packages/react/src/components/HelpText/HelpText.stories.mdx b/packages/react/src/components/HelpText/HelpText.stories.mdx index 4fd0c8c1d0..4e5440f275 100644 --- a/packages/react/src/components/HelpText/HelpText.stories.mdx +++ b/packages/react/src/components/HelpText/HelpText.stories.mdx @@ -20,6 +20,9 @@ import {ArgsTable} from "@storybook/addon-docs"; title: { description: 'Tittel som gis til hjelp-ikonet som kan leses av skjermlesere for tilgjengelighet.', }, + size: { + description: 'Set the size of the help-text button.', + }, placement: { description: 'Bestemmer hvilken side popoveren skal plasseres på, samt om plasseringen skal rettes inn etter hvor triggeren starter eller slutter.', }, diff --git a/packages/react/src/components/HelpText/HelpText.tsx b/packages/react/src/components/HelpText/HelpText.tsx index 7251dfd409..2678b729c8 100644 --- a/packages/react/src/components/HelpText/HelpText.tsx +++ b/packages/react/src/components/HelpText/HelpText.tsx @@ -4,12 +4,19 @@ import cn from 'classnames'; import { HelptextFilled, Helptext } from '@navikt/ds-icons'; import { Popover, PopoverVariant } from '../Popover'; +import utilClasses from '../../utils/utility.module.css'; import classes from './HelpText.module.css'; +export enum HelpTextSize { + Xsmall = 'xsmall', + Small = 'small', +} + export interface HelpTextProps extends ButtonHTMLAttributes { children: string; - title?: string; + title: string; + size?: HelpTextSize; placement?: | 'top' | 'bottom' @@ -31,6 +38,7 @@ export const HelpText = ({ title, placement = 'right', onClick, + size = HelpTextSize.Small, ...rest }: HelpTextProps) => { const [open, setOpen] = useState(false); @@ -54,16 +62,18 @@ export const HelpText = ({ className={cn( classes.helpTextIcon, classes.helpTextIconFilled, + classes[size], className, )} - title={title} data-state={open ? 'open' : 'closed'} + aria-hidden={true} /> + {title} } > diff --git a/packages/react/src/components/RadioButton/RadioButton.stories.mdx b/packages/react/src/components/RadioButton/RadioButton.stories.mdx index 2cc1de4dac..166016b610 100644 --- a/packages/react/src/components/RadioButton/RadioButton.stories.mdx +++ b/packages/react/src/components/RadioButton/RadioButton.stories.mdx @@ -41,6 +41,9 @@ import {ArgsTable} from "@storybook/addon-docs"; description: 'Gir radioknappen en rød ramme for å indikere en feil.', control: {type: 'boolean'} }, + helpText: { + description: 'Legger på en hjelpe-tekst knapp ved siden av labelen til radioknappen.', + }, hideLabel: { description: 'Skjuler teksten til høyre for radioknappen, men gjør den tilgjengelig for verktøy som skjermlesere.', control: {type: 'boolean'} @@ -99,6 +102,15 @@ Radioknappene kan ha flere forskjellige statuser: > {Template.bind({})}
+ + {Template.bind({})} + {Template.bind({})} @@ -104,7 +107,7 @@ Kun én knapp kan være trykket inn av gangen. {Template.bind({})} @@ -114,7 +117,25 @@ Kun én knapp kan være trykket inn av gangen. + {Template.bind({})} + + + +### Med hjelpetekst + + {Template.bind({})} @@ -124,7 +145,7 @@ Kun én knapp kan være trykket inn av gangen. {Template.bind({})} diff --git a/packages/react/src/components/RadioGroup/RadioGroup.tsx b/packages/react/src/components/RadioGroup/RadioGroup.tsx index 365f151bd4..75c13c7b9a 100644 --- a/packages/react/src/components/RadioGroup/RadioGroup.tsx +++ b/packages/react/src/components/RadioGroup/RadioGroup.tsx @@ -29,6 +29,7 @@ export interface RadioGroupProps { description?: ReactNode; disabled?: boolean; error?: ReactNode; + helpText?: string; items: RadioGroupItem[]; legend?: ReactNode; name: string; @@ -43,6 +44,7 @@ export const RadioGroup = ({ description, disabled, error, + helpText, items, legend, name, @@ -84,6 +86,7 @@ export const RadioGroup = ({ description={description} disabled={disabled} error={error} + helpText={helpText} legend={legend} size={fieldSetSize} > @@ -101,6 +104,7 @@ export const RadioGroup = ({ checked={radio.value === checkedValue} disabled={disabled || radio.disabled} error={!!error} + helpText={radio.helpText} key={radio.value} name={name} onChange={changeHandler(radio.value)} diff --git a/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.module.css b/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.module.css index c8f1b53b75..27e42d42df 100644 --- a/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.module.css +++ b/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.module.css @@ -77,6 +77,13 @@ color: var(--label-color); } +.labelAndHelpText { + display: inline-flex; + flex-direction: row; + gap: var(--gap); + align-items: center; +} + .description { color: var(--description-color); } @@ -88,7 +95,7 @@ } } -.template:not(.disabled):has(:focus-visible) { +.template:not(.disabled):not(:has(button:focus-visible)):has(:focus-visible) { outline: 2px solid var(--interactive_components-colors-focus_outline); outline-offset: 2px; } diff --git a/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.tsx b/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.tsx index 56be89a7d5..fcfbda6cb4 100644 --- a/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.tsx +++ b/packages/react/src/components/_CheckboxRadioTemplate/CheckboxRadioTemplate.tsx @@ -7,6 +7,9 @@ import type { ChangeEventHandler, ReactNode } from 'react'; import React, { useId } from 'react'; import cn from 'classnames'; +import { HelpText } from '../HelpText'; +import { HelpTextSize } from '../HelpText/HelpText'; + import classes from './CheckboxRadioTemplate.module.css'; export enum CheckboxRadioTemplateSize { @@ -20,6 +23,7 @@ export interface CheckboxRadioTemplateProps { className?: string; description?: ReactNode; disabled?: boolean; + helpText?: string; hideInput?: boolean; hideLabel?: boolean; inputId?: string; @@ -39,6 +43,7 @@ export const CheckboxRadioTemplate = ({ className, description, disabled, + helpText, hideInput, hideLabel, inputId, @@ -57,6 +62,10 @@ export const CheckboxRadioTemplate = ({ const showLabel = label && !hideLabel; const shouldHaveClickableLabel = !presentation || (typeof label !== 'object' && typeof description !== 'object'); + const helpTextSize = + size === CheckboxRadioTemplateSize.Xsmall + ? HelpTextSize.Xsmall + : HelpTextSize.Small; return ( - - {children} - + {children} )} {(showLabel || description) && ( {showLabel && ( - - {label} + + + {label} + + {helpText && ( + + {helpText} + + )} )} {description && ( diff --git a/packages/react/src/utils/utility.module.css b/packages/react/src/utils/utility.module.css new file mode 100644 index 0000000000..a45d5195be --- /dev/null +++ b/packages/react/src/utils/utility.module.css @@ -0,0 +1,13 @@ +/** + * Visually hide an element, but leave it available for screen readers + */ +.visuallyHidden { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + padding: 0; + position: absolute; + white-space: nowrap; + width: 1px; +}