"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > Creating a Smooth Transitioning Dialog Component in React (Part )

Creating a Smooth Transitioning Dialog Component in React (Part )

Published on 2024-07-29
Browse:145

Creating a Smooth Transitioning Dialog Component in React (Part )

Part 1: Setting Up the Basic Dialog Component with Minimize/Expand Functionality

Welcome to the first part of my four-part series on creating a responsive dialog component in React. In this series, I'll explore different approaches to achieve smooth animation transitions while maintaining the dialog's fluid dimensions. In this initial part, I'll set up the basic dialog component with minimise and expand functionality.

Please note that accessibility and responsive design are not included as part of the considerations in this series. The primary focus is on creating a reusable dialog component with smooth animation transitions.

This series is part of a proof of concept I've been working on, aimed at discussing and refining techniques for animating UI components. I invite feedback and insights from fellow developers to validate my approach or suggest improvements.

Setting Up the Basic Dialog Component

Let's start by creating a highly reusable dialog component that supports minimising and expanding. I'll use the compositional pattern to ensure the dialog can adapt to changing content.

File Structure:

src/
  components/
    FluidDialog/
      Dialog.js
      DialogContext.js
      DialogHeader.js
      DialogBody.js
      DialogFooter.js
      DialogContainer.js
      index.js
  App.js
  index.js

Step 1: Dialog Context

First, I'll create a context to manage the state of our dialog component.

Key Points:

  • The DialogContext will hold the state and provide functions to toggle the dialog between minimised and expanded states.
  • The DialogProvider component initialises the state and provides it to the dialog components via context.
// src/components/FluidDialog/DialogContext.js
import { createContext, useContext, useId, useState } from 'react';

const DialogContext = createContext();

export function DialogProvider({
  rootRef,
  isExpandedByDefault,
  children,
  maxWidth,
}) {
  const dialogId = useId();
  const [isExpanded, setIsExpanded] = useState(isExpandedByDefault);

  return (
    
      {children}
    
  );
}

export function useDialog() {
  return useContext(DialogContext);
}

Step 2: Dialog Component

Next, I'll create the main dialog component that uses the context to handle expansion and minimisation.

Key Points:

  • The Dialog component initialises the context provider with relevant props.
  • The DialogComponent styled-component handles the basic styling and layout of the dialog.
// src/components/FluidDialog/Dialog.js
import { useRef } from 'react';
import { styled } from 'styled-components';
import { DialogProvider } from './DialogContext';

export default function Dialog({
  id,
  isExpandedByDefault = true,
  maxWidth = 400,
  children,
}) {
  const rootRef = useRef(null);
  return (
    
      
        {children}
      
    
  );
}

const DialogComponent = styled.section`
  max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}px` : undefined)};
  position: absolute;
  right: 16px;
  bottom: 16px;
  border: 1px solid #ccc;
  border-radius: 6px;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.35);
  overflow: hidden;
`;

Step 3: Additional Components

I'll create additional components for the dialog header, body, footer, and container to ensure modularity and reusability.

Key Points:

  • DialogHeader includes a button to toggle between minimised and expanded states using the context.
  • DialogContainer wraps the body and footer content to automatically hide them when the isExpanded value is changed.
  • DialogBody and DialogFooter components are simple containers for the dialog's content.
// src/components/FluidDialog/DialogHeader.js
import { styled } from 'styled-components';
import { IconButton } from '../IconButton';
import { useDialog } from './DialogContext';

export default function DialogHeader({ children, expandedTitle }) {
  const { dialogId, isExpanded, setIsExpanded } = useDialog();

  return (
    
      
        {expandedTitle ?? children}
        
           setIsExpanded(false)}
          />
        
      
       setIsExpanded(true)}
      >
        {children}
        
          
        
      
    
  );
}

const DialogHeaderComponent = styled.div``;

const ExpandedState = styled.header`
  transition: opacity 0.3s;
  opacity: ${({ isVisible }) => (isVisible ? 1 : 0)};
  pointer-events: ${({ isVisible }) => (isVisible ? 'all' : 'none')};
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  background: #f3f3f3;
  display: flex;
  flex-direction: row;
`;

const MinimizedState = styled.header`
  transition: opacity 0.3s;
  opacity: ${({ isVisible }) => (isVisible ? 1 : 0)};
  pointer-events: ${({ isVisible }) => (isVisible ? 'all' : 'none')};
  background: #f3f3f3;
  display: flex;
  flex-direction: row;
  cursor: pointer;
`;

const Title = styled.span`
  flex-grow: 1;
  text-align: left;
  display: flex;
  align-items: center;
  padding: 0 16px;
`;

const IconButtons = styled.div``;
// src/components/FluidDialog/DialogContainer.js
import { styled } from 'styled-components';
import { useDialog } from './DialogContext';

export default function DialogContainer({ children }) {
  const { isExpanded } = useDialog();

  return (
    
      {children}
    
  );
}

const DialogContainerComponent = styled.div`
  display: ${({ isVisible }) => (isVisible ? undefined : 'none')};
`;
// src/components/FluidDialog/DialogBody.js
import { styled } from 'styled-components';
import DialogContainer from './DialogContainer';
import { useDialog } from './DialogContext';

export default function DialogBody({ children }) {
  const { dialogId } = useDialog();

  return (
    
      
        
          {children}
        
      
    
  );
}

const DialogBodyComponent = styled.div``;

const DialogBodyContent = styled.div`
  padding: 8px 16px;
`;
// src/components/FluidDialog/DialogFooter.js
import { styled } from 'styled-components';
import DialogContainer from './DialogContainer';

export default function DialogFooter({ children }) {
  return (
    
      
        {children}
      
    
  );
}

const DialogFooterComponent = styled.div`
  background: #f3f3f3;
`;

const DialogFooterContent = styled.div`
  padding: 8px 16px;
`;

Step 4: Putting It All Together

Finally, I'll import and use the dialog component in the main app.

Key Points:

  • The App component includes the Dialog with its header, body, and footer components.
  • This setup ensures the dialog is ready for further enhancements and animations in the upcoming parts.
// src/App.js
import React from 'react';
import Dialog from './components/FluidDialog/Dialog';
import DialogHeader from './components/FluidDialog/DialogHeader';
import DialogBody from './components/FluidDialog/DialogBody';
import DialogFooter from './components/FluidDialog/DialogFooter';

function App() {
  return (
    
My dialog/DialogHeader> This is the content of the dialog. This is the footer of the dialog.
); } export default App;
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  
    
  ,
  document.getElementById('root')
);

You can access the whole source code on CodeSandbox.

You can also see a live preview of the implementation:

Conclusion

In this first part, I've set up a basic dialog box in React with minimise and expand functionality. This foundational component will serve as the basis for further enhancements in the upcoming articles. The dialog component is designed to hug its content and adapt to changes, making it highly reusable and flexible.

Stay tuned for Part 2, where I'll delve into adding animations to the dialog transitions, exploring different options to achieve smooth effects.

I invite feedback and comments from fellow developers to help refine and improve this approach. Your insights are invaluable in making this proof of concept more robust and effective.

Release Statement This article is reproduced at: https://dev.to/copet80/creating-a-smooth-transitioning-dialog-component-in-react-part-14-7nd?1 If there is any infringement, please contact [email protected] to delete it
Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3