diff --git a/pro/src/ui-kit/MultiSelect/MultiSelect.module.scss b/pro/src/ui-kit/MultiSelect/MultiSelect.module.scss
new file mode 100644
index 00000000000..72908199f50
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/MultiSelect.module.scss
@@ -0,0 +1,149 @@
+@use "styles/mixins/_fonts.scss" as fonts;
+@use "styles/mixins/fonts-design-system.scss" as fonts-design-system;
+@use "styles/mixins/_rem.scss" as rem;
+@use "styles/mixins/_a11y.scss" as a11y;
+@use "styles/mixins/_size.scss" as size;
+
+.container {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  max-width: 400px;
+  position: relative;
+}
+
+.legend {
+  // @include fonts-design-system.body;
+  @include fonts.body;
+
+  color: var(--color-black);
+  margin-bottom: 8px;
+}
+
+.trigger {
+  @include fonts.body;
+
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px;
+  background-color: var(--color-white);
+  border: 1px solid var(--color-grey-dark);
+  border-radius: 10px;
+  width: 100%;
+  cursor: pointer;
+
+  &:disabled {
+    background-color: var(--color-grey-light);
+    border: none;
+    color: var(--color-black);
+  }
+
+  &:hover {
+    background: var(--color-grey-light);
+  }
+
+  &:focus {
+    border: 1px solid var(--color-black);
+  }
+
+  &:focus-visible {
+    outline: rem.torem(1px) solid var(--color-input-text-color);
+    outline-offset: rem.torem(2px);
+    border-radius: rem.torem(8px);
+    border: 1px solid var(--color-grey-dark);
+  }
+
+  &-selected {
+    border: 2px solid var(--color-black);
+  }
+}
+
+.trigger-content {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  max-width: 500px;
+}
+
+.trigger-label {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.badge {
+  // @include fonts-design-system.body-semi-bold-xs;
+  @include fonts.caption;
+
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 20px;
+  height: 20px;
+  background-color: var(--color-primary);
+  color: var(--color-white);
+  border-radius: 50%;
+}
+
+.chevron {
+  width: 16px;
+  height: 16px;
+  color: var(--color-black);
+}
+
+.chevron-open {
+  transform: rotate(180deg);
+}
+
+.item {
+  display: block;
+  width: 100%;
+  text-align: left;
+  font-size: 14px;
+  background: none;
+  border: none;
+  cursor: pointer;
+}
+
+.checkbox {
+  padding-top: rem.torem(16px);
+}
+
+.tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.panel {
+  position: absolute;
+  background-color: var(--color-white);
+  left: 0;
+  right: 0;
+  top: rem.torem(48px);
+  box-shadow: 0 rem.torem(3px) rem.torem(4px) var(--color-medium-shadow);
+  padding: rem.torem(24px);
+}
+
+.search-example {
+  // @include fonts-design-system.body-semi-bold-xs;
+  @include fonts.caption;
+
+  display: block;
+  min-height: rem.torem(16px);
+  color: var(--color-grey-dark);
+  padding-top: 8px;
+  padding-bottom: 24px;
+}
+
+.visually-hidden {
+  @include a11y.visually-hidden;
+}
+
+.separator {
+  height: rem.torem(1px);
+  background: var(--color-grey-medium);
+  margin-top: rem.torem(12px);
+}
diff --git a/pro/src/ui-kit/MultiSelect/MultiSelect.spec.tsx b/pro/src/ui-kit/MultiSelect/MultiSelect.spec.tsx
new file mode 100644
index 00000000000..ffc4c57bf9c
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/MultiSelect.spec.tsx
@@ -0,0 +1,29 @@
+import { screen } from '@testing-library/react'
+import { axe } from 'vitest-axe'
+
+import {
+  renderWithProviders,
+  RenderWithProvidersOptions,
+} from 'commons/utils/renderWithProviders'
+
+import { MultiSelect } from './MultiSelect'
+
+const renderMultiSelect = (options?: RenderWithProvidersOptions) => {
+  return renderWithProviders(<MultiSelect />, { ...options })
+}
+
+describe('<MultiSelect />', () => {
+  it('should render correctly', async () => {
+    renderMultiSelect()
+
+    expect(
+      await screen.findByRole('heading', { name: /MultiSelect/ })
+    ).toBeInTheDocument()
+  })
+
+  it('should not have accessibility violations', async () => {
+    const { container } = renderMultiSelect()
+
+    expect(await axe(container)).toHaveNoViolations()
+  })
+})
diff --git a/pro/src/ui-kit/MultiSelect/MultiSelect.stories.tsx b/pro/src/ui-kit/MultiSelect/MultiSelect.stories.tsx
new file mode 100644
index 00000000000..0040eefe920
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/MultiSelect.stories.tsx
@@ -0,0 +1,59 @@
+import { StoryObj } from '@storybook/react'
+import { withRouter } from 'storybook-addon-remix-react-router'
+
+import { MultiSelect } from './MultiSelect'
+
+export default {
+  title: 'ui-kit/MultiSelect',
+  decorators: [withRouter],
+  component: MultiSelect,
+  parameters: {
+    docs: {
+      story: {
+        inline: false,
+        iframeHeight: 380,
+      },
+    },
+  },
+}
+
+const defaultOptions = [
+  { id: '1', label: '78 - Yvelines' },
+  { id: '2', label: '75 - Paris' },
+  { id: '3', label: '44 - Nantes' },
+  { id: '4', label: '76 - Rouen' },
+  { id: '5', label: '77 - Seine et Marne' },
+]
+
+const defaultProps = {
+  options: defaultOptions,
+  legend: 'Département',
+  label: 'Selectionner un département',
+}
+
+export const Default: StoryObj<typeof MultiSelect> = {
+  args: {
+    ...defaultProps,
+  },
+}
+
+export const WithDefaultOptions: StoryObj<typeof MultiSelect> = {
+  args: {
+    ...defaultProps,
+    defaultOptions: [
+      { id: '2', label: '75 - Paris' },
+      { id: '3', label: '44 - Nantes' },
+    ],
+  },
+}
+
+export const WithSearchInput: StoryObj<typeof MultiSelect> = {
+  args: {
+    ...defaultProps,
+    hasSearch: true,
+    searchExample: 'Ex : 44 - Nantes',
+    searchLabel: 'Rechercher des départements',
+    legend: 'Départements',
+    label: 'Selectionner des départements',
+  },
+}
diff --git a/pro/src/ui-kit/MultiSelect/MultiSelect.tsx b/pro/src/ui-kit/MultiSelect/MultiSelect.tsx
new file mode 100644
index 00000000000..d69d4e692bf
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/MultiSelect.tsx
@@ -0,0 +1,190 @@
+import { useEffect, useRef, useState } from 'react'
+
+import { SelectedValuesTags } from 'ui-kit/form/SelectAutoComplete/SelectedValuesTags/SelectedValuesTags'
+
+import styles from './MultiSelect.module.scss'
+import { MultiSelectPanel } from './MultiSelectPanel'
+import { MultiSelectTrigger } from './MultiSelectTrigger'
+
+export type Option = {
+  id: string
+  label: string
+}
+
+type MultiSelectProps = {
+  options: Option[]
+  defaultOptions?: Option[]
+  label: string
+  legend: string
+  hasSearch?: boolean
+  searchExample?: string
+  searchLabel?: string
+  hasSelectAllOptions?: boolean
+  disabled?: boolean
+}
+
+export const MultiSelect = ({
+  options,
+  defaultOptions,
+  hasSearch,
+  searchExample,
+  searchLabel,
+  label,
+  legend,
+  hasSelectAllOptions,
+  disabled,
+}: MultiSelectProps): JSX.Element => {
+  const [isOpen, setIsOpen] = useState(false)
+  const containerRef = useRef<HTMLFieldSetElement>(null)
+  const [selectedItems, setSelectedItems] = useState<Option[]>(
+    defaultOptions ?? []
+  )
+
+  const handleSelectOrRemoveItem = (item: Option | 'all' | undefined) => {
+    if (item === 'all') {
+      setSelectedItems(options)
+    } else if (item === undefined) {
+      setSelectedItems([])
+    } else {
+      setSelectedItems((prev) =>
+        prev.some((prevItem) => prevItem.id === item.id)
+          ? prev.filter((prevItem) => prevItem.id !== item.id)
+          : [...prev, item]
+      )
+    }
+  }
+
+  const handleRemoveItem = (itemId: string) => {
+    setSelectedItems((prev) => prev.filter((item) => item.id !== itemId))
+  }
+
+  const toggleDropdown = () => setIsOpen(!isOpen)
+
+  const handleKeyDown = (event: React.KeyboardEvent) => {
+    if (event.key === 'Enter' || event.key === ' ') {
+      toggleDropdown()
+    }
+  }
+
+  useEffect(() => {
+    const handleWindowClick = (event: MouseEvent) => {
+      if (
+        containerRef.current &&
+        !containerRef.current.contains(event.target as Node)
+      ) {
+        setIsOpen(false)
+      }
+    }
+
+    const handleKeyDown = (event: KeyboardEvent) => {
+      if (event.key === 'Escape') {
+        setIsOpen(false)
+      }
+    }
+
+    window.addEventListener('click', handleWindowClick)
+    window.addEventListener('keydown', handleKeyDown)
+
+    return () => {
+      window.removeEventListener('click', handleWindowClick)
+      window.removeEventListener('keydown', handleKeyDown)
+    }
+  }, [])
+
+  return (
+    <fieldset
+      className={styles['container']}
+      style={{ position: 'relative' }}
+      ref={containerRef}
+    >
+      <MultiSelectTrigger
+        legend={legend}
+        label={label}
+        isOpen={isOpen}
+        toggleDropdown={toggleDropdown}
+        handleKeyDown={handleKeyDown}
+        selectedCount={selectedItems.length}
+        disabled={disabled}
+      />
+
+      {isOpen && (
+        <MultiSelectPanel
+          label={label}
+          options={options.map((option) => ({
+            ...option,
+            checked: selectedItems.some((item) => item.id === option.id),
+          }))}
+          onOptionSelect={handleSelectOrRemoveItem}
+          hasSearch={hasSearch}
+          searchExample={searchExample}
+          searchLabel={searchLabel}
+          hasSelectAllOptions={hasSelectAllOptions}
+        />
+      )}
+
+      <SelectedValuesTags
+        disabled={disabled}
+        selectedOptions={selectedItems.map((item) => item.id)}
+        removeOption={handleRemoveItem}
+        fieldName="tags"
+        optionsLabelById={selectedItems.reduce(
+          (acc, item) => ({ ...acc, [item.id]: item.label }),
+          {}
+        )}
+      />
+    </fieldset>
+  )
+}
+
+{
+  /* <fieldset>
+	<legend><button aria-controls="control-id" aria-expanded=...>Label du bouton</button></legend>
+	<div id="control-id">
+		<label class="visually-hidden" for="id-input">Rechercher des ...</label>
+		<svg> // icon visuelle
+		<input type="search" id="id-input"/>
+		<ul>
+			<li><input /> <label>...</label></li>
+			<li></li>
+			<li></li>
+		</ul>
+	</div>
+</fieldset>
+<div
+  role="listbox"
+  tabindex="0"
+  id="listbox1"
+  onclick="return listItemClick(event);"
+  onkeydown="return listItemKeyEvent(event);"
+  onkeypress="return listItemKeyEvent(event);"
+  onfocus="this.className='focus';"
+  onblur="this.className='blur';"
+  aria-activedescendant="listbox1-1">
+  <div role="option" id="listbox1-1" class="selected">Vert</div>
+  <div role="option" id="listbox1-2">Orange</div>
+  <div role="option" id="listbox1-3">Rouge</div>
+  <div role="option" id="listbox1-4">Bleu</div>
+  <div role="option" id="listbox1-5">Violet</div>
+  <div role="option" id="listbox1-6">Pervenche</div>
+</div>
+*/
+}
+
+{
+  /* <div className={styles.container} role="listbox" aria-label="Liste des départements">
+      {departments.map(department => (
+        <label key={department.id} className={styles.item}>
+          <div className={styles.checkbox}>
+            <input
+              type="checkbox"
+              checked={department.checked}
+              onChange={() => handleCheckboxChange(department.id)}
+              className={styles.input}
+            />
+            <span className={styles.checkmark} aria-hidden="true" />
+          </div>
+          <span className={styles.label}>{department.name}</span>
+        </label>
+      ))}
+    </div> */
+}
diff --git a/pro/src/ui-kit/MultiSelect/MultiSelectPanel.tsx b/pro/src/ui-kit/MultiSelect/MultiSelectPanel.tsx
new file mode 100644
index 00000000000..b2558bf13f0
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/MultiSelectPanel.tsx
@@ -0,0 +1,101 @@
+import { useMemo, useState } from 'react'
+
+import strokeSearch from 'icons/stroke-search.svg'
+import { BaseCheckbox } from 'ui-kit/form/shared/BaseCheckbox/BaseCheckbox'
+import { BaseInput } from 'ui-kit/form/shared/BaseInput/BaseInput'
+
+import { Option } from './MultiSelect'
+import styles from './MultiSelect.module.scss'
+
+type MultiSelectPanelProps = {
+  className?: string
+  label: string
+  options: (Option & { checked: boolean })[]
+  onOptionSelect: (option: Option | 'all' | undefined) => void
+  hasSearch?: boolean
+  searchExample?: string
+  searchLabel?: string
+  hasSelectAllOptions?: boolean
+}
+
+export const MultiSelectPanel = ({
+  options,
+  onOptionSelect,
+  hasSearch = false,
+  searchExample,
+  searchLabel,
+  hasSelectAllOptions,
+}: MultiSelectPanelProps): JSX.Element => {
+  const [searchValue, setSearchValue] = useState('')
+  const [isSelectAllChecked, setIsSelectAllChecked] = useState(false)
+  const searchedValues = useMemo(
+    () =>
+      options.filter((option) =>
+        option.label.toLowerCase().includes(searchValue.toLowerCase())
+      ),
+    [options, searchValue]
+  )
+
+  const onToggleAllOptions = (checked: boolean) => {
+    if (checked) {
+      onOptionSelect(undefined)
+    } else {
+      onOptionSelect('all')
+    }
+    setIsSelectAllChecked(!checked)
+  }
+
+  const onToggleOption = (option: Option, checked: boolean) => {
+    if (checked) {
+      setIsSelectAllChecked(false)
+    }
+    onOptionSelect(option)
+  }
+
+  return (
+    <div className={styles['panel']}>
+      {hasSearch && (
+        <>
+          <label className={styles['visually-hidden']} htmlFor="search-input">
+            {searchLabel}
+          </label>
+          <BaseInput
+            type="search"
+            id="search-input"
+            leftIcon={strokeSearch}
+            value={searchValue}
+            onChange={(e) => setSearchValue(e.target.value)}
+          />
+          <span className={styles['search-example']}>{searchExample}</span>
+        </>
+      )}
+
+      {searchedValues.length > 0 ? (
+        <ul className={styles['container']} aria-label="Liste des options">
+          {hasSelectAllOptions && (
+            <li key={'all-options'} className={styles['item']}>
+              <BaseCheckbox
+                label={'Tout sélectionner'}
+                checked={isSelectAllChecked}
+                onChange={() => onToggleAllOptions(isSelectAllChecked)}
+              />
+              <div className={styles['separator']} />
+            </li>
+          )}
+          {searchedValues.map((option) => (
+            <li key={option.id} className={styles.item}>
+              <BaseCheckbox
+                className={styles['checkbox']}
+                label={option.label}
+                checked={option.checked}
+                onChange={() => onToggleOption(option, option.checked)}
+              />
+            </li>
+          ))}
+        </ul>
+      ) : (
+        <span>{'Aucun résultat trouvé pour votre recherche.'}</span>
+      )}
+    </div>
+  )
+}
diff --git a/pro/src/ui-kit/MultiSelect/MultiSelectTrigger.tsx b/pro/src/ui-kit/MultiSelect/MultiSelectTrigger.tsx
new file mode 100644
index 00000000000..2b17e7275b8
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/MultiSelectTrigger.tsx
@@ -0,0 +1,61 @@
+import cn from 'classnames'
+import { useId } from 'react'
+
+import fullDownIcon from 'icons/full-down.svg'
+import fullUpIcon from 'icons/full-up.svg'
+import { SvgIcon } from 'ui-kit/SvgIcon/SvgIcon'
+
+import styles from './MultiSelect.module.scss'
+
+type MultiSelectTriggerProps = {
+  isOpen: boolean
+  selectedCount: number
+  toggleDropdown: () => void
+  handleKeyDown: (event: React.KeyboardEvent) => void
+  legend: string
+  label: string
+  disabled?: boolean
+}
+
+export const MultiSelectTrigger = ({
+  isOpen,
+  selectedCount,
+  toggleDropdown,
+  handleKeyDown,
+  legend,
+  label,
+  disabled,
+}: MultiSelectTriggerProps): JSX.Element => {
+  const legendId = useId()
+  return (
+    <>
+      <legend id={legendId} className={styles['legend']}>
+        {legend}
+      </legend>
+      <button
+        type="button"
+        className={cn(styles['trigger'], {
+          [styles['trigger-selected']]: selectedCount > 0,
+        })}
+        onClick={toggleDropdown}
+        onKeyDown={handleKeyDown}
+        aria-haspopup="listbox"
+        aria-expanded={isOpen}
+        aria-labelledby={legendId}
+        disabled={disabled}
+      >
+        <div className={styles['trigger-content']}>
+          {selectedCount > 0 && (
+            <div className={styles['badge']}>{selectedCount}</div>
+          )}
+          <span className={styles['trigger-label']}>{label}</span>
+        </div>
+        <SvgIcon
+          className={`${styles['chevron']} ${isOpen ? styles['chevronOpen'] : ''}`}
+          alt=""
+          src={isOpen ? fullUpIcon : fullDownIcon}
+        />
+      </button>
+    </>
+  )
+}
diff --git a/pro/src/ui-kit/MultiSelect/TODO.md b/pro/src/ui-kit/MultiSelect/TODO.md
new file mode 100644
index 00000000000..8d5e7655cba
--- /dev/null
+++ b/pro/src/ui-kit/MultiSelect/TODO.md
@@ -0,0 +1,18 @@
+Fonctionnel
+
+- [] gérer la navigation clavier
+- [] jsdoc
+- [] ne pas afficher plus de 3 lignes de tags
+
+Design
+
+- [] corriger la zone de clic sur BaseCheckbox
+- [] corriger le curseur de BaseCheckbox
+- [] ajuster la hauteur des checkbox
+- [] nettoyage du design (marges, variant violet du tag, variant violet du badge, stroke, fichier scss)
+- [] utiliser les fonts du design system
+- [] gérer le responsive
+
+Bonus
+
+- [] typage des props hasSearch et searchExample
diff --git a/pro/src/ui-kit/form/shared/BaseCheckbox/BaseCheckbox.module.scss b/pro/src/ui-kit/form/shared/BaseCheckbox/BaseCheckbox.module.scss
index 0ba32fb7202..dd33c9e69e9 100644
--- a/pro/src/ui-kit/form/shared/BaseCheckbox/BaseCheckbox.module.scss
+++ b/pro/src/ui-kit/form/shared/BaseCheckbox/BaseCheckbox.module.scss
@@ -7,10 +7,14 @@
 .base-checkbox {
   display: inline-flex;
   cursor: pointer;
+  height: 100%;
+  width: 100%;
 
   &-label-row {
     display: inline-flex;
     align-items: flex-start;
+    height: 100%;
+    width: 100%;
 
     &-with-description {
       align-items: center;
@@ -20,6 +24,7 @@
   &-label {
     display: flex;
     flex-direction: column;
+    height: 100%;
     width: 100%;
 
     &-with-description {