diff --git a/.storybook/select.stories.tsx b/.storybook/select.stories.tsx
new file mode 100644
index 0000000..0365c52
--- /dev/null
+++ b/.storybook/select.stories.tsx
@@ -0,0 +1,52 @@
+import { ThemeProvider } from 'styled-components';
+import { Select, SelectChild } from '../src/index';
+import { theme } from '../src/theme';
+import { GlobalStyles } from '../src/globalStyles';
+import type { Meta, StoryObj } from '@storybook/react-vite';
+import React from 'react';
+
+const meta = {
+ component: Select,
+ decorators: [
+ (Story) => (
+
+
+
+
+
+
+ ),
+ ],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ value: 'option1',
+ $onChange: (value) => {},
+ },
+ render: (args) => (
+
+ ),
+};
+
+export const WithLabel: Story = {
+ args: {
+ value: 'option1',
+ $onChange: (value) => {},
+ $labelContent: 'Pick option...',
+ },
+ render: (args) => (
+
+ ),
+};
diff --git a/src/components/Select/Select.tsx b/src/components/Select/Select.tsx
new file mode 100644
index 0000000..88a387f
--- /dev/null
+++ b/src/components/Select/Select.tsx
@@ -0,0 +1,94 @@
+import {
+ SelectButtonComponent,
+ SelectButtonLabelComponent,
+ SelectListComponent,
+} from './styles.js';
+import React, {
+ Children,
+ cloneElement,
+ isValidElement,
+ useEffect,
+ useRef,
+ useState,
+ type ReactElement,
+} from 'react';
+import type { SelectChildProps, SelectProps } from './types.js';
+import { KeyboardArrowDown, KeyboardArrowUp } from '@mui/icons-material';
+
+export const Select = ({
+ $fullWidth = false,
+ value,
+ $onChange,
+ children,
+ $labelContent,
+}: SelectProps) => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const parentComponentRef = useRef(null);
+
+ const displayValue = React.useMemo(() => {
+ // Function for memorizing display value of currently selected child
+ return (
+ Object.values(children as object).find(
+ (child) => child.props.value === value,
+ ).props.children || 'N/F'
+ );
+ }, [value, children]);
+
+ const handleOptionClick = (optionValue: string) => {
+ $onChange(optionValue);
+ setIsOpen(false);
+ };
+
+ const handleUnfocus = (event: PointerEvent) => {
+ if (!parentComponentRef.current?.contains(event.target as Node)) {
+ setIsOpen(false);
+ }
+ };
+
+ useEffect(() => {
+ if (parentComponentRef.current === null) return;
+ setTimeout(() => {
+ document.addEventListener('click', handleUnfocus);
+ }, 0);
+
+ return () => document.removeEventListener('click', handleUnfocus);
+ }, [isOpen]);
+
+ return (
+
+ {$labelContent !== undefined && (
+ {$labelContent}
+ )}
+
+ setIsOpen(!isOpen)}>
+ {displayValue}
+ {isOpen ? (
+
+ ) : (
+
+ )}
+
+ {isOpen && (
+
+ {Children.map(children, (child) => {
+ if (!isValidElement(child)) return child;
+
+ return cloneElement(child as ReactElement, {
+ $CURRENT_VALUE: value,
+ $HANDLE_CLICK: handleOptionClick,
+ });
+ })}
+
+ )}
+
+ );
+};
diff --git a/src/components/Select/SelectChild.tsx b/src/components/Select/SelectChild.tsx
new file mode 100644
index 0000000..cdee80f
--- /dev/null
+++ b/src/components/Select/SelectChild.tsx
@@ -0,0 +1,26 @@
+import { SelectChildWrapper } from './styles.js';
+import type { SelectChildProps } from './types.js';
+import React from 'react';
+
+export const SelectChild = ({
+ children,
+ $CURRENT_VALUE,
+ $HANDLE_CLICK,
+ value,
+}: SelectChildProps) => {
+ const handleClick = () => {
+ if ($HANDLE_CLICK === undefined)
+ throw new Error('$ON_CHANGE prop is undefined');
+
+ $HANDLE_CLICK(value);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/components/Select/styles.ts b/src/components/Select/styles.ts
new file mode 100644
index 0000000..1fbf864
--- /dev/null
+++ b/src/components/Select/styles.ts
@@ -0,0 +1,67 @@
+import { styled } from 'styled-components';
+import { theme } from '../../theme.js';
+
+export const SelectButtonComponent = styled.button`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ background-color: ${theme.colors.main};
+ border: 1px solid ${theme.colors.lightGray};
+ padding: 4px 8px;
+ border-radius: 6px;
+
+ &:focus {
+ color: ${theme.colors.primary};
+ border: 1px solid ${theme.colors.primary};
+ }
+
+ width: 100%;
+`;
+
+export const SelectButtonLabelComponent = styled.label`
+ width: 100%;
+ font-size: 10pt;
+ padding: 8px;
+ color: ${theme.colors.lightGray};
+
+ &:has(+ button:focus) {
+ color: ${theme.colors.primary};
+ text-decoration: underline;
+ }
+`;
+
+export const SelectListComponent = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ position: absolute;
+ top: calc(100% + 5px);
+ left: 0;
+ width: 100%;
+ outline: 1px solid ${theme.colors.lightGray};
+ border-radius: 6px;
+
+ & > *:not(:last-child) {
+ border-bottom: 1px solid ${theme.colors.lightGray};
+ }
+`;
+
+export const SelectChildWrapper = styled.button<{ $isCurrentValue: boolean }>`
+ display: flex;
+ align-items: center;
+ justify-content: start;
+ width: 100%;
+ background-color: ${theme.colors.main};
+ border: none;
+ padding: 8px;
+ cursor: pointer;
+
+ ${({ $isCurrentValue }) =>
+ $isCurrentValue &&
+ `border-color: ${theme.colors.primary}; color: ${theme.colors.primary}`};
+
+ &:hover {
+ background-color: ${theme.colors.mainDimmed};
+ }
+`;
diff --git a/src/components/Select/types.ts b/src/components/Select/types.ts
new file mode 100644
index 0000000..a4e445b
--- /dev/null
+++ b/src/components/Select/types.ts
@@ -0,0 +1,14 @@
+import type { ComponentPropsWithoutRef, ComponentPropsWithRef } from 'react';
+
+export interface SelectProps extends ComponentPropsWithRef<'select'> {
+ $fullWidth?: boolean;
+ $labelContent?: string;
+ value: string;
+ $onChange: (value: string) => void;
+}
+
+export interface SelectChildProps extends ComponentPropsWithRef<'button'> {
+ value: string;
+ $HANDLE_CLICK?: (value: string) => void;
+ $CURRENT_VALUE?: string;
+}
diff --git a/src/index.tsx b/src/index.tsx
index 8964e4a..02047d1 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,3 +1,5 @@
export { Button } from './components/Button/Button.js';
export { Link } from './components/Link/Link.js';
export { Input } from './components/Input/Input.js';
+export { Select } from './components/Select/Select.js';
+export { SelectChild } from './components/Select/SelectChild.js';