Position

The Position component is a utility meant to help one control position of elements relative to other elements, for example, tooltips above a button.

  • Install
    npm install @pluralsight/ps-design-system-position
  • Import
    import { Above, AboveLeft, AboveRight, Below, BelowLeft, BelowRight, LeftOf, RightOf } from '@pluralsight/ps-design-system-position'

Examples

Using the React component

The component that you pass to the show prop must be wrapped in React.forwardRef and allow the style prop to be set.

import React, { useState } from 'react'
import Button from '@pluralsight/ps-design-system-button'
import Tooltip from '@pluralsight/ps-design-system-tooltip'
import { RightOf } from '@pluralsight/ps-design-system-position'
const Example: React.FC = props => {
const [hovered, setHovered] = useState(false)
const hide = () => setHovered(false)
const show = () => setHovered(true)
return (
<RightOf
show={
<Tooltip tailPosition={Tooltip.tailPositions.leftCenter}>
Tooltip
</Tooltip>
}
when={hovered}
>
<Button
appearance={Button.appearances.secondary}
onMouseEnter={show}
onMouseLeave={hide}
>
Hover me
</Button>
</RightOf>
)
}
export default Example

Portal override

Position always renders in a portal, defaulting to document.body. It is often desirable to provide your own node to render within. Use the inNode prop to pass an element reference.

import React, { forward, useLayoutEffect, useRef, useState } from 'react'
import Button from '@pluralsight/ps-design-system-button'
import { PlaceholderIcon } from '@pluralsight/ps-design-system-icon'
import Tooltip from '@pluralsight/ps-design-system-tooltip'
import { Above } from '@pluralsight/ps-design-system-position'
const Example: React.FC = props => {
const portal = useRef<HTMLDivElement>()
const [hasRendered, setHasRendered] = useState(false)
useLayoutEffect(() => {
setHasRendered(true)
}, [])
return (
<React.Fragment>
{hasRendered && (
<div className="example">
<Above
inNode={portal.current}
show={<Tooltip>Rendered in portal</Tooltip>}
>
<Target />
</Above>
</div>
)}
<div ref={portal} />
<style jsx>{`
.example {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 200px;
outline: 2px dashed lightgrey;
}
`}</style>
</React.Fragment>
)
}
const Target = forwardRef<HTMLButtonElement>((_props, ref) => (
<Button
appearance={Button.appearances.flat}
disabled
icon={<PlaceholderIcon />}
title="Target"
ref={ref}
/>
))
export default Example

Javascript Example

The most important bits of this utility are available in pure JavaScript.

import {
above,
aboveLeft,
aboveRight,
above,
belowLeft,
belowRight,
leftOf,
rightOf
} from '@pluralsight/ps-design-system-position'

Use the JavaScript function to get the positioning style desired.

import React, { useEffect, useRef, useState } from 'react'
import Button from '@pluralsight/ps-design-system-button'
import Tooltip from '@pluralsight/ps-design-system-tooltip'
import { rightOf } from '@pluralsight/ps-design-system-position'
const Example: React.FC = props => {
const button = useRef<HTMLButtonElement>()
const tooltip = useRef<HTMLDivElement>()
const [hovered, setHovered] = useState(false)
const hide = () => setHovered(false)
const show = () => setHovered(true)
const [style, setStyle] = useState({ position: 'absolute' })
useEffect(() => {
if (!button.current || !tooltip.current) return
const nextStyle = rightOf(button.current).styleFor(tooltip.current)
setStyle(nextStyle)
}, [hovered])
return (
<div>
<Button
appearance={Button.appearances.secondary}
onMouseEnter={show}
onMouseLeave={hide}
ref={button}
>
Hover me
</Button>
<Tooltip
ref={tooltip}
style={{ ...style, display: hovered ? 'block' : 'none' }}
visible={false}
>
Tooltip
</Tooltip>
</div>
)
}
export default Example

Allow Offscreen

The allowOffscreen property allows a developer to enable rendering content outside the viewport. This is useful when you want to render a tooltip open on page load and the tooltip should render below the fold.

import React, { useState } from 'react'
import Button from '@pluralsight/ps-design-system-button'
import Tooltip from '@pluralsight/ps-design-system-tooltip'
import { RightOf } from '@pluralsight/ps-design-system-position'
const Example: React.FC = props => {
const [hovered, setHovered] = useState(true)
const hide = () => setHovered(false)
const show = () => setHovered(true)
return (
<React.Fragment>
<RightOf
allowOffscreen={true}
show={
<Tooltip tailPosition={Tooltip.tailPositions.leftCenter}>
Tooltip open on load
</Tooltip>
}
when={hovered}
>
<Button
appearance={Button.appearances.secondary}
onMouseEnter={show}
onMouseLeave={hide}
>
Hover me
</Button>
</RightOf>
<style jsx>{`
.example {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 200px;
outline: 2px dashed lightgrey;
}
`}</style>
</React.Fragment>
)
}
const Target = forwardRef<HTMLButtonElement>((_props, ref) => (
<Button
appearance={Button.appearances.flat}
disabled
icon={<PlaceholderIcon />}
title="Target"
ref={ref}
/>
))
export default Example

Positions

Props

Name
Type
Description
Default
allowOffscreenbooleanallow rendering of positioned element offscreenfalse
children
Required
React.ReactNodetarget element something will be relative to
inNodeHTMLElementspecific node for portal renderingdocument.body
show
Required
React.ReactNodeelement placed in relation to target
targetRefreference to custom target
whenbooleanconditional rendering of positioned elementtrue