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 (<RightOfshow={<Tooltip tailPosition={Tooltip.tailPositions.leftCenter}>Tooltip</Tooltip>}when={hovered}><Buttonappearance={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"><AboveinNode={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) => (<Buttonappearance={Button.appearances.flat}disabledicon={<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) returnconst nextStyle = rightOf(button.current).styleFor(tooltip.current)setStyle(nextStyle)}, [hovered])return (<div><Buttonappearance={Button.appearances.secondary}onMouseEnter={show}onMouseLeave={hide}ref={button}>Hover me</Button><Tooltipref={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><RightOfallowOffscreen={true}show={<Tooltip tailPosition={Tooltip.tailPositions.leftCenter}>Tooltip open on load</Tooltip>}when={hovered}><Buttonappearance={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) => (<Buttonappearance={Button.appearances.flat}disabledicon={<PlaceholderIcon />}title="Target"ref={ref}/>))export default Example
Positions
Props
Name | Type | Description | Default |
---|---|---|---|
allowOffscreen | boolean | allow rendering of positioned element offscreen | false |
children Required | React.ReactNode | target element something will be relative to |
|
inNode | HTMLElement | specific node for portal rendering | document.body |
show Required | React.ReactNode | element placed in relation to target |
|
target | Ref | reference to custom target |
|
when | boolean | conditional rendering of positioned element | true |