diff --git a/packages/docs-app/src/examples/select-examples/selectExample.tsx b/packages/docs-app/src/examples/select-examples/selectExample.tsx
index 293aa55a39..1c4dc41204 100644
--- a/packages/docs-app/src/examples/select-examples/selectExample.tsx
+++ b/packages/docs-app/src/examples/select-examples/selectExample.tsx
@@ -34,6 +34,7 @@ export interface ISelectExampleState {
     resetOnSelect: boolean;
     disableItems: boolean;
     disabled: boolean;
+    matchTargetWidth: false;
 }
 
 export class SelectExample extends React.PureComponent<IExampleProps, ISelectExampleState> {
@@ -45,6 +46,7 @@ export class SelectExample extends React.PureComponent<IExampleProps, ISelectExa
         disabled: false,
         filterable: true,
         hasInitialContent: false,
+        matchTargetWidth: false,
         minimal: false,
         resetOnClose: false,
         resetOnQuery: true,
@@ -71,6 +73,8 @@ export class SelectExample extends React.PureComponent<IExampleProps, ISelectExa
 
     private handleResetOnSelectChange = this.handleSwitchChange("resetOnSelect");
 
+    private handleMatchTargetWidthChange = this.handleSwitchChange("matchTargetWidth");
+
     public render() {
         const { allowCreate, disabled, disableItems, minimal, ...flags } = this.state;
 
@@ -124,6 +128,11 @@ export class SelectExample extends React.PureComponent<IExampleProps, ISelectExa
                     checked={this.state.disableItems}
                     onChange={this.handleItemDisabledChange}
                 />
+                <Switch
+                    label="Match target width"
+                    checked={this.state.matchTargetWidth}
+                    onChange={this.handleMatchTargetWidthChange}
+                />
                 <Switch
                     label="Allow creating new items"
                     checked={this.state.allowCreate}
diff --git a/packages/select/src/common/classes.ts b/packages/select/src/common/classes.ts
index 47d5ab0daa..00c9e1ee9b 100644
--- a/packages/select/src/common/classes.ts
+++ b/packages/select/src/common/classes.ts
@@ -25,3 +25,4 @@ export const OMNIBAR = `${NS}-omnibar`;
 export const OMNIBAR_OVERLAY = `${OMNIBAR}-overlay`;
 export const SELECT = `${NS}-select`;
 export const SELECT_POPOVER = `${SELECT}-popover`;
+export const SELECT_MATCH_TARGET_WIDTH = `${SELECT}-match-target-width`;
diff --git a/packages/select/src/components/select/_select.scss b/packages/select/src/components/select/_select.scss
index f4f009dae6..128ad07885 100644
--- a/packages/select/src/components/select/_select.scss
+++ b/packages/select/src/components/select/_select.scss
@@ -7,6 +7,15 @@ $select-popover-max-height: $pt-grid-size * 30 !default;
 $select-popover-max-width: $pt-grid-size * 40 !default;
 
 .#{$ns}-select-popover {
+  &.#{$ns}-select-match-target-width {
+    width: 100%;
+
+    .#{$ns}-menu {
+      max-width: none;
+      min-width: 0;
+    }
+  }
+
   .#{$ns}-popover-content {
     // use padding on container rather than margin on input group
     // because top margin leaves some empty space with no background color.
diff --git a/packages/select/src/components/select/select.tsx b/packages/select/src/components/select/select.tsx
index e03ac779a1..a2cd1125a9 100644
--- a/packages/select/src/components/select/select.tsx
+++ b/packages/select/src/components/select/select.tsx
@@ -63,6 +63,16 @@ export interface ISelectProps<T> extends IListItemsProps<T> {
      */
     inputProps?: InputGroupProps2;
 
+    /**
+     * Whether the select popover should be styled so that it matches the width of the target.
+     * This is done using a popper.js modifier passed through `popoverProps`.
+     *
+     * Note that setting `matchTargetWidth={true}` will also set `popoverProps.usePortal={false}` and `popoverProps.wrapperTagName="div"`.
+     *
+     * @default false
+     */
+    matchTargetWidth?: boolean;
+
     /** Props to spread to `Popover`. Note that `content` cannot be changed. */
     // eslint-disable-next-line @typescript-eslint/ban-types
     popoverProps?: Partial<IPopoverProps> & object;
@@ -129,7 +139,31 @@ export class Select<T> extends AbstractPureComponent2<SelectProps<T>, ISelectSta
 
     private renderQueryList = (listProps: IQueryListRendererProps<T>) => {
         // not using defaultProps cuz they're hard to type with generics (can't use <T> on static members)
-        const { filterable = true, disabled = false, inputProps = {}, popoverProps = {} } = this.props;
+        const {
+            filterable = true,
+            disabled = false,
+            inputProps = {},
+            popoverProps = {},
+            matchTargetWidth,
+        } = this.props;
+
+        if (matchTargetWidth) {
+            if (popoverProps.modifiers == null) {
+                popoverProps.modifiers = {};
+            }
+
+            popoverProps.modifiers.minWidth = {
+                enabled: true,
+                fn: data => {
+                    data.styles.width = `${data.offsets.reference.width}px`;
+                    return data;
+                },
+                order: 800,
+            };
+
+            popoverProps.usePortal = false;
+            popoverProps.wrapperTagName = "div";
+        }
 
         const input = (
             <InputGroup
@@ -155,7 +189,9 @@ export class Select<T> extends AbstractPureComponent2<SelectProps<T>, ISelectSta
                 {...popoverProps}
                 className={classNames(listProps.className, popoverProps.className)}
                 onInteraction={this.handlePopoverInteraction}
-                popoverClassName={classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName)}
+                popoverClassName={classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName, {
+                    [Classes.SELECT_MATCH_TARGET_WIDTH]: matchTargetWidth,
+                })}
                 onOpening={this.handlePopoverOpening}
                 onOpened={this.handlePopoverOpened}
                 onClosing={this.handlePopoverClosing}