Component Structure

Overview


General

Location of layout and utility/reusable components: /src/components/ Location of page-related components: /src/pages/[page]/_components/

Notes:

  • Only 1 exported function per component file (the main/"exported" component)

    • If needing to reuse a local component/function/variable/type in another file, it should then be be moved to their own file at that time (and moved to their proper location)

  • Use named export (vs default export) [1][2][3]

  • Use Props as the name for exported component's interface/type

    • For additional local components, append "Props" to the local component name LocalComponentNameProps

  • Destructure top-level props within signature (vs first line destructuring)

    • Then, use first-line destructuring for destructuring individual top-level props when needed

// ...
// ...
// ...

Template

// Imports

// Constants (Preference 1)

interface Props {}

export function ComponentName({}: Props) {
  // Constants (Preference 2)
  // Hooks
  // State
  // Effects
  // Functions (Preference 2)
  // Constants (Preference 3) (e.g. variables that depend on local state/effects)
  // Render Logic (e.g. isLoading, isError, isDisabled, etc.)
  return (
    <>
      {/* Render */}
    </>
  );
}

// Functions (Preference 1)
// - Components (first)
// - Functions (second)

Example

See MUI Styled Components example


MUI styled components

When creating a utility/reusable component with an MUI component as the "base" component:

  • .Props interface should extend the MUI component's native props

import { Button, type ButtonProps } from '@mui/material'
interface Props extends ButtonProps {...}
  • Destructure the sx prop from ...props (within the component signature/declaration)

export function MuiComponentAdjective({ sx, ...props }: Props) {
    ...
}
  • Pass in the destructured sx prop into the MuiComponent's sx prop after any "default" sx styling

    • Otherwise, passing the sx prop to an instance of the MuiComponent will override any "default" sx prop styling that exists

export function MuiComponentAdjective({ sx, ...props }: Props) {
    <MuiComponent
        sx={{
          // any "default" sx styling for styled MUI component
          ...sx
        }}
        {...props} 
    >
}

Template

import { MuiComponent, type MuiComponentProps } from '@mui/material';

interface Props extends MuiComponentProps {
  // any unique fields that are not included within MuiComponentProps (aka not a native prop to the MuiComponent)
}

export function MuiComponentAdjective({ uniqueField, sx, ...props }: Props) {
  return (
    <>
      <MuiComponent
        // data-testid="muicomponent-adjective" (when needed for testing)
        // any "default" props for styled MUI component
        sx={{
          // any "default" sx styling for styled MUI component
          ...sx, // allows overriding of "default" sx styling (e.g. scenario where changing the margin would result in better aesthetics on a specific instance of MuiComponentAdjective
        }}
        {...props} // allows overriding of "default" props
      >
        {...}
      </MuiComponent>
    </>
  );
}

Example

import { IconButton, type IconButtonProps } from '@mui/material';
import { Icon } from './Icon';

interface Props extends IconButtonProps {
  handleClose: () => void;
}

export function IconButtonClose({ handleClose, sx, props }: Props) {
  return (
    <>
      <IconButton
        data-testid="button-close"
        color="inherit"
        size="small"
        onClick={() => handleClose()}
        edge="end"
        sx={{
          opacity: 0.6,
          ...sx,
        }}
        {...props}
      >
        <Icon icon="close" />
      </IconButton>
    </>
  );
}

Last updated