# Centering rows around a specific element using React

(You can view the source code for this example and try it out yourself in [this Replit](https://replit.com/@scowalt/Centering-things#src/App.tsx))

Let's say we have a DOM structure like this:
```html
<Row>
  <A>A</A>
  <B>B</B>
  <C>C</C>
</Row>
```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1655567915784/WB7_VDKHD.png align="left")

(vertical line added to illustrate the center of the page)

How do we make it such that all of the all of the elements in the row are _centered around_ `<B>`?


You might try a naive approach - just center all of the elements of the row!
```ts
const Row = styled.div`
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: center;
`
```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1655567946735/77jAXKvm1.png align="left")

This approach _would_ work if `<A>`, `<B>`, and `<C>` shared the same width. However, the layout engine will center the _row as a whole_, and the middle of that entire row doesn't fall in the middle of `<B>`. Ideally, we would have the layout engine ignore `<A>` and `<C>` when computing how to center the `<Row>`

Fortunately, there _is_ a way for us to have the layout engine ignore an element when aligning a document! That way is `position: absolute` [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/CSS/position#absolute):

```ts
const A = styled(Box)`
  width: 100px;
  background-color: blue;
  position: absolute;
`;

const B = styled(Box)`
  width: 80px;
  background-color: green;
`;

const C = styled(Box)`
  width: 60px;
  background-color: red;
  position: absolute;
`;
```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1655568031647/WvHdrwUgN.png align="left")

Okay, new problem. We have successfully centered the `<Row>` around `<B>`, but the layout engine now doesn't know where to put `<A>` and `<C>`! In order to horizontally position `<A>` and `<C>`, we're going to need to do some of the work of the layout engine. This is where React comes in.

There are two React APIs that we're going to make use of:

1. [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref), which will give us references to all of the elements we want to use.
2. [`useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect), which allows us to change the positions of `<A>` and `<C>` whenever needed.

First, we'll take our references: 
```ts
export default function App() {
  const aRef = useRef<HTMLDivElement>(null);
  const bRef = useRef<HTMLDivElement>(null);
  const cRef = useRef<HTMLDivElement>(null);
  
  return <Page className="app">
    <VerticalLine />
    <Content>
      <Row>
        <A ref={aRef}>A</A>
        <B ref={bRef}>B</B>
        <C ref={cRef}>C</C>
      </Row>
    </Content>
  </Page>;
}
```

Next, inside of `App()`, we'll install our listener to `useLayoutEffect` (credit to [Joe Purnell](https://dev.to/joepurnell1/programmatically-positioning-elements-with-react-hooks-aef) for this technique):
```ts
  function updatePosition() {
    /** TODO */
  }
  
  useLayoutEffect(() => {
    window.addEventListener("resize", updatePosition);
    updatePosition();
    return () => window.removeEventListener("resize", updatePosition);
  }, []);
```

Now that we have the ability to move each element (`useRef`), and the event listener for _when_ to move each element (`useLayoutEffect`), we just need to know _where_ to move each element.

Inside of `updatePosition()`, we want to move the _right edge_ of `<A>` to the _left edge_ of `<B>`, and the _left edge_ of `<C>` to _right edge_ of `<B>`: 
```ts
function updatePosition() {
    const leftEdgeOfB =
      bRef.current!.getBoundingClientRect().left +
      bRef.current!.getBoundingClientRect().width;
      // I'm not sure why the width needs to be added 🤷
    aRef.current!.style.right = `${leftEdgeOfB}px`;
    
    const rightEdgeOfB =
      bRef.current!.getBoundingClientRect().right;
    cRef.current!.style.left = `${rightEdgeOfB}px`;
}
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1655569740160/FA6j9dViY.png align="left")

Done! Now `<A>` and `<C>` will always be properly aligned, even if the DOM moves around while the page is loaded.

The source code for this example is available [here](https://replit.com/@scowalt/Centering-things#src/App.tsx). To see this technique in action (at time of writing), check out my website, [scowalt.com](https://scowalt.com/).

