diff --git a/PopupContainer/PopupContainer.js b/PopupContainer/PopupContainer.js
new file mode 100644
index 0000000000..a869a3335f
--- /dev/null
+++ b/PopupContainer/PopupContainer.js
@@ -0,0 +1,205 @@
+/**
+ * Modal component available with free positioning.
+ *
+ * @example
+ *
+ *
+ * {* App Contents *}
+ *
+ *
+ *
+ * @module sandstone/PopupContainer
+ * @exports PopupContainer
+ * @exports PopupContainerBase
+ */
+
+import {forward, forwardCustom} from '@enact/core/handle';
+import kind from '@enact/core/kind';
+// import {I18nContextDecorator} from '@enact/i18n/I18nDecorator';
+import FloatingLayer from '@enact/ui/FloatingLayer';
+import PropTypes from 'prop-types';
+import {Component} from 'react';
+
+import css from './PopupContainer.module.less';
+
+/**
+ *
+ * @class PopupContainerBase
+ * @memberof sandstone/PopupContainer
+ * @ui
+ * @private
+ */
+const PopupContainerBase = kind({
+ name: 'PopupContainerBase',
+
+ propTypes: /** @lends sandstone/PopupContainer.PopupContainerBase.prototype */ {
+ /**
+ * Force direction like ltr, rtl.
+ *
+ * @type {String}
+ * @public
+ */
+ forceDirection: PropTypes.string,
+
+ /**
+ * Position of the PopupContainer on the screen.
+ *
+ * @type {Object}
+ * @public
+ */
+ position: PropTypes.object,
+
+ /**
+ * Whether rtl locale.
+ *
+ * @type {Boolean}
+ * @private
+ */
+ rtl: PropTypes.bool
+ },
+
+ defaultProps: {
+ position: {left: 0, top: 0}
+ },
+
+ styles: {
+ css,
+ className: 'container'
+ },
+
+ computed: {
+ style: ({position, rtl, forceDirection}) => {
+ if (forceDirection === 'rtl') {
+ return {transform: `translate(${position.left * (-1)}px,${position.top}px`};
+ }
+ if (forceDirection === 'ltr') {
+ return {transform: `translate(${position.left}px,${position.top}px`};
+ }
+ if (rtl) {
+ return {transform: `translate(${position.left * (-1)}px,${position.top}px`};
+ }
+ if (!rtl) {
+ return {transform: `translate(${position.left}px,${position.top}px`};
+ }
+ },
+ directionStyle: ({forceDirection, rtl}) => {
+ if (forceDirection) return {direction : forceDirection};
+ if (!forceDirection && rtl) return {direction: 'rtl'};
+ if (!forceDirection && !rtl) return {direction: 'ltr'};
+ }
+ },
+
+ render: ({children, directionStyle, ...rest}) => {
+ delete rest.forceDirection;
+ delete rest.position;
+ delete rest.rtl;
+
+ return (
+
+ );
+ }
+});
+
+// const I18nPopupContainer = I18nContextDecorator(
+// {rtlProp: 'rtl'},
+// PopupContainerBase
+// );
+
+/**
+ *
+ * @class PopupContainer
+ * @memberof sandstone/PopupContainer
+ * @extends sandstone/PopupContainerBase
+ * @ui
+ * @private
+ */
+class PopupContainer extends Component {
+
+ static propTypes = /** @lends sandstone/PopupContainer.PopupContainer.prototype */ {
+ /**
+ * Force direction like rtl, ltr.
+ *
+ * @type {String}
+ * @public
+ */
+ forceDirection: PropTypes.string,
+
+ /**
+ * Called when the user has attempted to close the popup.
+ *
+ * @type {Function}
+ * @public
+ */
+ onClose: PropTypes.func,
+
+ /**
+ * Called when the popup is opened.
+ *
+ * @type {Function}
+ * @public
+ */
+ onOpen: PropTypes.func,
+
+ /**
+ * Controls the visibility of the PopupContainer.
+ *
+ * By default, the PopupContainer and its contents are not rendered until `open`.
+ *
+ * @type {Boolean}
+ * @default false
+ * @public
+ */
+ open: PropTypes.bool,
+
+ /**
+ * Position of the PopupContainer on the screen.
+ *
+ * @type {Object}
+ * @public
+ */
+ position: PropTypes.object
+ };
+
+ static defaultProps = {
+ open: false,
+ position: {left: 0, top: 0}
+ };
+
+ constructor (props) {
+ super(props);
+ }
+
+ handleClose = (ev) => {
+ forwardCustom('onClose')(ev, this.props);
+ };
+
+ handleOpen = (ev) => {
+ forward('onOpen', ev, this.props);
+ };
+
+ render () {
+ const {open, children, ...rest} = this.props;
+ delete rest.onClose;
+ delete rest.onOpen;
+
+ return (
+
+
+ {children}
+
+
+ );
+ }
+}
+
+export default PopupContainer;
+export {PopupContainer, PopupContainerBase};
diff --git a/PopupContainer/PopupContainer.module.less b/PopupContainer/PopupContainer.module.less
new file mode 100644
index 0000000000..79ed12ad23
--- /dev/null
+++ b/PopupContainer/PopupContainer.module.less
@@ -0,0 +1,7 @@
+// PopupContainer.module.less
+
+.PopupContainer {
+ .container {
+ position: absolute;
+ }
+}
diff --git a/PopupContainer/package.json b/PopupContainer/package.json
new file mode 100644
index 0000000000..81d4e61cc6
--- /dev/null
+++ b/PopupContainer/package.json
@@ -0,0 +1,3 @@
+{
+ "main": "PopupContainer.js"
+}
diff --git a/PopupContainer/tests/PopupContainer-specs.js b/PopupContainer/tests/PopupContainer-specs.js
new file mode 100644
index 0000000000..d7ff3e706a
--- /dev/null
+++ b/PopupContainer/tests/PopupContainer-specs.js
@@ -0,0 +1,35 @@
+import {FloatingLayerDecorator} from '@enact/ui/FloatingLayer';
+
+import '@testing-library/jest-dom';
+import {render, screen} from '@testing-library/react';
+
+import {PopupContainer} from '../PopupContainer';
+
+const FloatingLayerController = FloatingLayerDecorator('div');
+
+describe('PopupContainer specs', () => {
+ test('should be rendered opened if open is set to true', () => {
+ render(
+
+ PopupContainer
+
+ );
+
+ const popupContainer = screen.getByText('PopupContainer');
+
+ expect(popupContainer).toBeInTheDocument();
+ });
+
+ test('should not be rendered if open is set to false', () => {
+ render(
+
+ PopupContainer
+
+ );
+
+ const popupContainer = screen.queryByText('PopupContainer');
+
+ expect(popupContainer).toBeNull();
+ });
+});
+
diff --git a/samples/sampler/stories/default/PopupContainer.js b/samples/sampler/stories/default/PopupContainer.js
new file mode 100644
index 0000000000..6f16583442
--- /dev/null
+++ b/samples/sampler/stories/default/PopupContainer.js
@@ -0,0 +1,73 @@
+import {I18nContextDecorator} from '@enact/i18n/I18nDecorator';
+import BodyText from '@enact/sandstone/BodyText';
+import PopupContainer from '@enact/sandstone/PopupContainer';
+import {mergeComponentMetadata} from '@enact/storybook-utils';
+import {action} from '@enact/storybook-utils/addons/actions';
+import {boolean, object} from '@enact/storybook-utils/addons/controls';
+
+import {svgGenerator} from '../helper/svg';
+import PropTypes from 'prop-types';
+
+const Config = mergeComponentMetadata('PopupContainer', PopupContainer);
+
+export default {
+ title: 'Sandstone/PopupContainer',
+ component: 'PopupContainer'
+};
+
+const AppImageContents = () =>
;
+const AppTextContents = () => This is text for popup contents
;
+
+const contentStyle = {
+ display: 'flex',
+ alignItems: 'center',
+ border: 'solid 1px',
+ borderRadius: '20px'
+};
+
+const PopupContents = () => (
+
+);
+
+const PopupContainerBaseSample = ({args}) => {
+ return (
+
+
+
+
+
Use CONTROLS to interact with PopupContainer.
+
+ );
+};
+
+PopupContainerBaseSample.propTypes = {
+ args: PropTypes.object,
+ rtl: PropTypes.bool
+};
+
+const PopupContainerSamples = I18nContextDecorator(
+ {rtlProp: 'rtl'},
+ PopupContainerBaseSample
+);
+
+export const _PopupContainer = (args) => ;
+
+boolean('open', _PopupContainer, Config);
+object('position', _PopupContainer, Config, {'left': 300, 'top': 300});
+// select('forceDirection', _PopupContainer,[null, 'ltr', 'rtl'], Config, null);
+
+_PopupContainer.storyName = 'PopupContainer';
+_PopupContainer.parameters = {
+ info: {
+ text: 'Basic usage of PopupContainer'
+ }
+};