Skip to content
Open
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
6 changes: 4 additions & 2 deletions apps/www/app/_components/live-component/live-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export type LiveComponentProps = {
story: string;
layout?: 'row' | 'column' | 'centered' | 'block';
language?: Language;
defaultOpen?: boolean;
startAsInert?: boolean /*to prevent focus on load of error-summary stories*/;
};

Expand Down Expand Up @@ -191,8 +192,8 @@ const Editor = ({ live, html, id, hidden, language }: EditorProps) => {
onChange={(v) => setShowHTML(v === 'true')}
data-color='neutral'
>
<ds.ToggleGroup.Item value='false'>React</ds.ToggleGroup.Item>
<ds.ToggleGroup.Item value='true'>HTML</ds.ToggleGroup.Item>
<ds.ToggleGroup.Item value='false'>React</ds.ToggleGroup.Item>
</ds.ToggleGroup>
<ds.Button
data-color='neutral'
Expand Down Expand Up @@ -299,11 +300,12 @@ export const LiveComponent = ({
story,
layout = 'centered',
language = 'react',
defaultOpen = false,
startAsInert,
}: LiveComponentProps) => {
const location = useLocation();
const { t } = useTranslation();
const [showEditor, setShowEditor] = useState(false);
const [showEditor, setShowEditor] = useState(defaultOpen);
const [colorScheme, setColorScheme] = useState<string | null>('dark');
const [invertedColorScheme, setInvertedColorScheme] = useState<string | null>(
'light',
Expand Down
11 changes: 2 additions & 9 deletions apps/www/app/_components/mdx-components/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,7 @@ export const MDXComponents = ({
);
};

const Story = ({
story,
layout,
language,
startAsInert,
}: LiveComponentProps) => {
const Story = ({ story, ...rest }: LiveComponentProps) => {
const { stories } = useLoaderData();
if (!stories) return null;

Expand All @@ -182,9 +177,7 @@ const Story = ({
return (
<LiveComponent
story={`${foundStory.code}\n\nrender(<${foundStory.name} />)`}
layout={layout}
language={language}
startAsInert={startAsInert}
{...rest}
/>
);
};
73 changes: 47 additions & 26 deletions apps/www/app/content/components/dropdown/dropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,27 @@ import { useState } from 'react';

export const Preview = () => {
return (
<Dropdown.TriggerContext>
<Dropdown.Trigger>Dropdown</Dropdown.Trigger>
<Dropdown placement='bottom-end'>
<Dropdown.Heading>First heading</Dropdown.Heading>
<>
<Button popovertarget='dropdown'>Dropdown</Button>
<Dropdown id='dropdown'>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Button 1.1</Dropdown.Button>
<Dropdown.Button>Item 1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 1.2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
<Dropdown.Heading>Second heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Button 2.1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 2.2</Dropdown.Button>
<Dropdown.Button>Item 2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</Dropdown.TriggerContext>
</>
);
};

export const Icons = () => {
return (
<Dropdown.TriggerContext>
<Dropdown.Trigger>Dropdown</Dropdown.Trigger>
<Dropdown>
<>
<Button popovertarget='dropdown-icons'>Dropdown</Button>
<Dropdown id='dropdown-icons'>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button asChild>
Expand Down Expand Up @@ -62,7 +52,35 @@ export const Icons = () => {
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</Dropdown.TriggerContext>
</>
);
};

export const Headings = () => {
return (
<>
<Button popovertarget='dropdown-headings'>Dropdown</Button>
<Dropdown id='dropdown-headings'>
<Dropdown.Heading>First heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Button 1.1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 1.2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
<Dropdown.Heading>Second heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Button 2.1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Button 2.2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</>
);
};

Expand Down Expand Up @@ -124,17 +142,20 @@ export const ControlledEn = () => {
);
};

export const WithoutTrigger = () => {
export const TriggerContext = () => {
return (
<>
<Button popovertarget='dropdown'>Dropdown</Button>
<Dropdown id='dropdown'>
<Dropdown.TriggerContext>
<Dropdown.Trigger>Trigger</Dropdown.Trigger>
<Dropdown>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
<Dropdown.Button>Item 1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Item 2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</>
</Dropdown.TriggerContext>
);
};
119 changes: 44 additions & 75 deletions apps/www/app/content/components/dropdown/en/code.mdx
Original file line number Diff line number Diff line change
@@ -1,60 +1,58 @@
<Story story="Preview" />
<ReactComponentDocs />
<Story story="Preview" language="html"/>

## Usage

`Dropdown` uses [`Popover`](/en/components/docs/popover/code) internally.

```tsx
import { Dropdown } from '@digdir/designsystemet-react';
<>
{/* with context */}
<Dropdown.TriggerContext>
<Dropdown.Trigger>Trigger</Dropdown.Trigger>
<Dropdown>
<Dropdown.Heading>Heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</Dropdown.TriggerContext>

{/* without context */}
<Button popovertarget="my-dropdown">Trigger</Button>
<Dropdown id="my-dropdown">
<Dropdown.Heading>Heading</Dropdown.Heading>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Item</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
</>
```
You can use the native popover API directly in HTML.
This can be used without JavaScript, if you don't want to polyfill.

Note that the element with `popover="manual"` uses two classes, `ds-popover` and `ds-dropdown`.

You choose whether you want to use `popover="manual"` or just `popover` to open the dropdown.

[Popover API (mozilla.org)](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using)

### React and `popovertarget`

When you use `popover` without `Dropdown.TriggerContext`, you link yourself trigger and `popover`.
Then `popovertarget` is used in lowercase, so that all versions of React correctly render the attribute.
When using `@digdir/designsystemet-react` we extend `@types/react-dom` to accept this.

### Polyfill

`Dropdown` uses the [Popover API (mozilla.org)](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/popover). This API is classified as [Baseline:
Newly available (mozilla.org)](https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility) as of April 2024,
with Firefox as the last browser to add it. In some cases, you may find that users are locked to older browser versions for various reasons, and then it may be appropriate to add a [Popover-Polyfill (github.com)](https://github.com/oddbird/popover-polyfill) to ensure that `Dropdown` works for everyone.

## Examples

### Controlled
## CSS variables and data attributes

If you submit `open`, then you use `Dropdown` controlled. You can use `onClose` to get notified when `Dropdown` wants to close.
<CssVariables />

Note that we do not use `onClick` on the trigger, the dropdown handles this internally and sends to `onOpen` and `onClose`.
<CssAttributes />

## React


Designsystemet offers a React implementation in the form of `Dropdown` that provides extra functionality in React.

```jsx
<Button popovertarget='dropdown'>Dropdown</Button>
<Dropdown id='dropdown'>
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>Item 1</Dropdown.Button>
</Dropdown.Item>
<Dropdown.Item>
<Dropdown.Button>Item 2</Dropdown.Button>
</Dropdown.Item>
</Dropdown.List>
</Dropdown>
```

### `popovertarget`

When you use `popover` without `Dropdown.TriggerContext`, you link yourself trigger and `popover`.
Then `popovertarget` is used in lowercase, so that all versions of React correctly render the attribute.
When using `@digdir/designsystemet-react` we extend `@types/react-dom` to accept this.

<Story story="ControlledEn" />

### Without `TriggerContext`

Expand All @@ -64,48 +62,19 @@ You must then add `popovertarget={id}` to `Dropdown`, and `id` to `Dropdown`.

<Story story="WithoutTrigger" />

## HTML

You can use the native popover API directly in HTML.
This can be used without JavaScript, if you don't want to polyfill.

Note that the element with `popover="manual"` uses two classes, `ds-popover` and `ds-dropdown`.

You choose whether you want to use `popover="manual"` or just `popover` to open the dropdown.
### Controlled

[Popover API (mozilla.org)](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using)
If you submit `open`, then you use `Dropdown` controlled. You can use `onClose` to get notified when `Dropdown` wants to close.

```html
<button
class="ds-button"
data-variant="primary"
type="button"
popovertarget="dropdown"
>Dropdown</button>
<div
class="ds-popover ds-dropdown"
id="dropdown"
popover="manual"
data-variant="default"
>
<ul>
<li>
<button
class="ds-button"
data-variant="tertiary"
type="button"
>Item</button>
</li>
</ul>
</div>
Note that we do not use `onClick` on the trigger, the dropdown handles this internally and sends to `onOpen` and `onClose`.

```
<Story story="ControlledEn" />

## CSS variables and data attributes
### Props

<CssVariables />
### Dropdown

<CssAttributes />
<ReactComponentDocs />

### References

Expand Down
16 changes: 11 additions & 5 deletions apps/www/app/content/components/dropdown/en/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ search_terms: select, menu, listbox, popup, dropdownmenu, options

<Story story="Preview" />

**Use `Dropdown` when**
**Use dropdown when**
- you want to offer multiple options without taking up much space in the interface
- the options are secondary but should still be easily accessible

**Avoid `Dropdown` when**
- an action is primary or frequently used; use a visible [`Button`](/en/components/docs/button/overview) instead
**Avoid dropdown when**
- an action is primary or frequently used; use a visible [button](/en/components/docs/button/overview) instead
- there is only one option, as a dropdown adds unnecessary complexity

## Example
Expand All @@ -20,11 +20,17 @@ You can use icons together with text in the dropdown items:

<Story story="Icons" />

### With groupings

You can use headings to group related items in the dropdown:

<Story story="Headings" />

## Guidelines

`Dropdown` does not create a semantic menu, but provides the foundation for building one yourself. Read the ["Menu and Menubar Pattern" on w3.org](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/) for more information on how to create accessible menus.
Dropdown does not create a semantic menu, but provides the foundation for building one yourself. Read the ["Menu and Menubar Pattern" on w3.org](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/) for more information on how to create accessible menus.

- Use `Dropdown` for actions or navigation that do not need to be visible at all times
- Use Dropdown for actions or navigation that do not need to be visible at all times
- Keep the number of items manageable
- Use headings to group related items
- Avoid multiple levels of dropdowns (nested menus)
4 changes: 2 additions & 2 deletions apps/www/app/content/components/dropdown/metadata.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"no": {
"title": "Dropdown",
"subtitle": "`Dropdown` er en generisk nedtrekksliste. Den legger grunnmuren for å bygge menyer og lister. "
"subtitle": "Dropdown er en generisk nedtrekksliste. Den legger grunnmuren for å bygge menyer og lister."
},
"en": {
"title": "Dropdown",
"subtitle": "`Dropdown` is a generic dropdown list. It lays the foundation for building menus and lists."
"subtitle": "Dropdown is a generic dropdown list. It lays the foundation for building menus and lists."
},
"image": "Dropdown.svg",
"cssFile": "dropdown.css"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ Det er innebygd tilgjengelighet i [Popover APIet](https://developer.mozilla.org/

### Tastatur

På grunn av forskjellige bruksmønstre for `Dropdown` har vi ikke innebygd tastaturhåndtering.
På grunn av forskjellige bruksmønstre for `dropdown` har vi ikke innebygd tastaturhåndtering.
Dersom du lager en meny må du selv implementere tastaturhåndtering for å navigere i menyen.
Se ["Menu and Menubar Pattern" hos w3c](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/).
Vi har [`RovingFocus`](/no/components/utilities/roving-focus) som er en hjelpekomponent for tastaturnavigasjon.

Dersom du bruker `Dropdown` uten å gjøre noe selv, vil fokuserbare elementer i `Dropdown.List` kunne navigeres med tabulator-tasten, og du kan lukke `Dropdown` med Escape-tasten.
Dersom du bruker `dropdown` uten å gjøre noe selv, vil fokuserbare elementer i `dropdown` listen kunne navigeres med tabulator-tasten, og du kan lukke `dropdown` med Escape-tasten.
Loading
Loading