-
-
Save segunadebayo/181cc82a5026d615200d246e1e04e4fa to your computer and use it in GitHub Desktop.
React Component Hooks API (from Reakit)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useTooltipState, Tooltip, TooltipArrow, TooltipReference } from "reakit"; | |
function App() { | |
const state = useTooltipState({ placement: "top" }); | |
return ( | |
<div> | |
<TooltipReference {...state}>Hover me</TooltipReference> | |
<Tooltip {...state}> | |
<TooltipArrow {...state} /> | |
Tooltip | |
</Tooltip> | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useAlert, mergeProps } from "reakit"; | |
function Confirm({ onConfirm, ...props }) { | |
// if backdrop is being used, alert.role is set to "alertdialog", instead of "alert" | |
// https://www.w3.org/TR/wai-aria-1.1/#alertdialog | |
const { alert, backdrop, closeButton, autoFocus, state } = useAlert(); | |
const handleConfirm = () => { | |
state.close(); | |
onConfirm(); | |
}; | |
return state.mounted ? ( | |
<React.Fragment> | |
<div {...backdrop} /> | |
<div {...mergeProps(alert, props)}> | |
{props.children} | |
<button {...mergeProps(autoFocus, { onClick: state.close })}>Cancel</button> | |
<button onClick={handleConfirm}>Confirm</button> | |
</div> | |
</React.Fragment> | |
) : null; | |
} | |
// return value of useAlert | |
const alert = { | |
alert: { | |
id: "alertid", // some auto generated id | |
role: "alert", // or "alertdialog" if backdrop.ref is truthy | |
hidden: true, | |
style: { | |
position: "fixed", // if it's alertdialog | |
display: "none" | |
} | |
}, | |
backdrop: { | |
ref: Ref, // if it's truthy, disables focus and scroll on the elements behind | |
role: "presentation", | |
hidden: true, | |
onClick: () => state.close() | |
}, | |
button: { | |
// uses useButton (which inclused ref, role, tabIndex etc.) | |
"aria-haspopup": "dialog", // if it's alertdialog | |
"aria-controls": "alertid", | |
"aria-expanded": "false", | |
onClick: () => state.toggle() | |
}, | |
autoFocus: { | |
ref: Ref, // uses it to .focus() when state.visible becomes true | |
tabIndex: 0 | |
}, | |
state: { | |
mounted: true, | |
transitioning: false, | |
visible: true, | |
open: () => {}, | |
close: () => {}, | |
toggle: () => {} | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useDropdown, useDropdownOption, mergeProps } from "reakit"; | |
// https://www.w3.org/TR/wai-aria-1.1/#listbox | |
// https://www.w3.org/TR/wai-aria-practices/#Listbox | |
function Dropdown(props) { | |
// list is portal | |
const { dropdown, button, list, state } = useDropdown(); | |
const option1 = useDropdownOption({ id: "option1", ...state }); | |
const option2 = useDropdownOption({ id: "option2", ...state }); | |
return ( | |
<div {...mergeProps(dropdown, props)}> | |
<button {...button} /> | |
{state.mounted && ( | |
<ul {...list}> | |
<li {...option1} /> | |
<li {...option2} /> | |
</ul> | |
)} | |
</div> | |
); | |
} | |
// return value of useDropdown | |
const dropdown = { | |
dropdown: { | |
// if input.ref is truthy (don't know what to do when it's not combobox) | |
// https://www.w3.org/TR/wai-aria-1.1/#combobox | |
role: "combobox", | |
"aria-expanded": "true", | |
"aria-haspopup": "listbox" // or grid | |
}, | |
button: { | |
// uses useButton (which inclused ref, role, tabIndex etc.) | |
role: "button", | |
onClick: () => state.toggle(), | |
"aria-controls": "listid" // or gridid | |
}, | |
input: { | |
role: "textbox", | |
onFocus: () => state.open(), | |
onBlur: () => state.close(), | |
onKeyPress: () => {}, // key arrows to select options | |
"aria-controls": "listid", // or gridid | |
"aria-autocomplete": "foo" // if autoComplete = true | |
}, | |
list: { | |
// return value of useDropdownList | |
role: "listbox", | |
id: "listid", // some auto generated id | |
onKeyPress: () => {} // key arrows if button.ref is truthy (not input, so focus goes here) | |
}, | |
grid: { | |
// return value of useGrid | |
role: "grid", | |
id: "gridid", | |
onKeyPress: () => {} // key arrows if button.ref is truthy (not input, so focus goes here) | |
}, | |
state: { | |
mounted: true, | |
transitioning: false, | |
visible: true, | |
open: () => {}, | |
close: () => {}, | |
toggle: () => {} | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useDropdown, useDropdownOption, mergeProps } from "reakit"; | |
function DropdownEditable(props) { | |
const { dropdown, input, list, state } = useDropdown({ autoComplete: true }); | |
const option1 = useDropdownOption({ id: "option1", ...state }); | |
const option2 = useDropdownOption({ id: "option2", ...state }); | |
return ( | |
<div {...mergeProps(dropdown, props)}> | |
<input {...input} /> | |
{state.mounted && ( | |
<ul {...list}> | |
<li {...option1} /> | |
<li {...option2} /> | |
</ul> | |
)} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useDropdown, useDropdownOption, mergeProps } from "reakit"; | |
function DropdownMulti(props) { | |
const { dropdown, input, list, state } = useDropdown({ multi: true }); | |
const option1 = useDropdownOption({ id: "option1", ...state }); | |
const option2 = useDropdownOption({ id: "option2", ...state }); | |
return ( | |
<div {...mergeProps(dropdown, props)}> | |
<ul> | |
{state.selected.map(option => ( | |
<li key={option}> | |
{option} | |
<button onClick={() => state.remove(option)}>x</button> | |
</li> | |
))} | |
</ul> | |
<input {...input} /> | |
{state.mounted && ( | |
<ul {...list}> | |
<li {...option1} /> | |
<li {...option2} /> | |
</ul> | |
)} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useGrid, useGridRow, useGridCell, mergeProps } from "reakit"; | |
function Cell({ state, ...props }) { | |
const cell = useGridCell(state); | |
return <div {...mergeProps(cell, props)} />; | |
} | |
function Row({ state, children, ...props }) { | |
const { row, state: rowState } = useGridRow(state); | |
return ( | |
<div {...mergeProps(row, props)}> | |
{children(state)} | |
</div> | |
); | |
} | |
// https://www.w3.org/TR/wai-aria-1.1/#grid | |
function Grid(props) { | |
const { grid, state } = useGrid(); | |
const data = { | |
row0: ["cell0", "cell1", "cell2"], | |
row1: ["cell0", "cell1", "cell2"], | |
row2: ["cell0", "cell1", "cell2"], | |
}; | |
return ( | |
<div {...mergeProps(grid, props)}> | |
{Object.entries(data).map(([row, cells]) => ( | |
<Row key={row} state={state}> | |
{rowState => cells.map(cell => ( | |
<Cell key={cell} state={rowState}>{cell}</Cell> | |
))} | |
</Row> | |
))} | |
</div> | |
); | |
} | |
// return value of useGrid | |
const grid = { | |
grid: { | |
role: "grid", | |
onKeyPress: () => {} | |
}, | |
state: { | |
rows: [ | |
[ref, ref, ref, ref, ref], | |
[ref, ref, ref, ref, ref] | |
], | |
addRow: () => {} | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useSkipNav } from "reakit"; | |
function Layout({ children }) { | |
const { skipNav, content } = useSkipNav(); | |
return ( | |
<React.Fragment> | |
<div {...skipNav} /> | |
<Nav /> | |
<div {...content}>{children}</div> | |
</React.Fragment> | |
); | |
} | |
// return value of useSkipNav | |
const skipNav = { | |
skipNav: { | |
tabIndex: 0, | |
onClick: () => {} | |
}, | |
content: { | |
id: "contentid" // useId (takes from a global map of refs) | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useDialog, mergeProps } from "reakit"; | |
function LoginModalButton(props) { | |
// all state hooks implement useContextState from Constate underneath | |
// this means that we can pass a "context" prop so as to access the shared state | |
const { button } = useDialog({ context: "login" }); | |
return <button {...mergeProps(button, props)} />; | |
} | |
function LoginModal(props) { | |
const { dialog, backdrop, autoFocus, state } = useDialog({ context: "login" }); | |
return state.mounted ? ( | |
<React.Fragment> | |
<div {...backdrop} /> | |
<div {...mergeProps(dialog, props)}> | |
<button {...mergeProps(autoFocus, { onClick: state.close })} /> | |
</div> | |
</React.Fragment> | |
) : null; | |
} | |
// return value of useDialog | |
const dialog = { | |
dialog: {}, | |
backdrop: {}, | |
autoFocus: {}, | |
state: {} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { usePopover, mergeProps } from "reakit"; | |
function Popover() { | |
// all main hooks (e.g. useModule) return a map of objects | |
// Popover is portal by default | |
// Popover is dialog by default | |
const { popover, arrow, button, state } = usePopover({ placement: "top" }); | |
return ( | |
<div> | |
<button {...button}>Toggle</button> | |
{state.mounted && ( | |
<div {...popover}> | |
<div {...arrow} /> | |
Popover | |
</div> | |
)} | |
</div> | |
); | |
} | |
// return value of usePopover | |
const popover = { | |
popover: {}, | |
arrow: {}, | |
button: {}, | |
state: {} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { | |
usePopoverState, | |
usePopoverArrow, | |
usePopoverButton, | |
usePopoverPopover | |
} from "reakit"; | |
function PopoverDecoupled() { | |
// hooks are decoupled so users can plug their own | |
// child hooks have a naming convention based on keys returned by the main hooks | |
// e.g. { state, arrow, button, popover } = usePopover(); | |
const state = usePopoverState({ placement: "top" }); | |
const arrow = usePopoverArrow(state); | |
const button = usePopoverButton(state); | |
const popover = usePopoverPopover(state); | |
return ( | |
<div> | |
<button {...button}>Toggle</button> | |
<div {...popover}> | |
<div {...arrow} /> | |
Popover | |
</div> | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { usePortal, mergeProps } from "reakit"; | |
// Popover, Tooltip, Dialog, Sidebar etc. all use portal by default | |
function Portal(props) { | |
const portal = usePortal(); | |
return <div {...mergeProps(portal, props)} /> | |
} | |
// return value of usePortal | |
const portal = {}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useProgress } from "reakit"; | |
// https://www.w3.org/TR/wai-aria-1.1/#progressbar | |
function Progress() { | |
const { progress, reference } = useProgress(); | |
return ( | |
<React.Fragment> | |
<div {...reference} /> {/* sets aria-busy and aria-describedby */} | |
<div {...progress} /> | |
</React.Fragment> | |
); | |
} | |
// return value of useProgress | |
const progress = { | |
progress: { | |
role: "progressbar", | |
id: "progressid" | |
}, | |
reference: { | |
"aria-busy": "true", | |
"aria-describedby": "progressid" | |
}, | |
state: {} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { Provider } from "reakit"; | |
import emotionPlugin from "reakit-plugin-emotion"; | |
const myOwnPlugin = { | |
usePopoverPopover: (input, output) => { | |
// It's OK to use inline style here. | |
// It'll be transformed later with emotionPlugin | |
const style = { color: "red" }; | |
return mergeProps(output, { style }); | |
} | |
} | |
const plugins = [myOwnPlugin, emotionPlugin]; | |
function App() { | |
return ( | |
<Provider plugins={plugins}> | |
... | |
</Provider> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { mergeProps } from "reakit"; | |
import { css } from "emotion"; | |
// It would be called on every Reakit hook | |
// Since Reakit hooks will return inline styles, it transforms them | |
// into className using emotion | |
export function useOutput(input, { style, ...output }) { | |
const className = css(style); | |
return mergeProps(output, { className }); | |
} | |
export default { useOutput }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useSteps, useStep } from "reakit"; | |
function Steps() { | |
const { steps, progress, previousButton, nextButton, state } = useSteps({ current: 0 }); | |
const first = useStep(state); | |
const second = useStep(state); | |
const third = useStep(state); | |
return ( | |
<div {...steps}> | |
<button {...previousButton}>Previous</button> | |
<button {...nextButton}>Next</button> | |
{first.state.mounted && <div {...first.step}>First</div>} | |
{second.state.mounted && <div {...second.step}>Second</div>} | |
{third.state.mounted && <div {...third.step}>Third</div>} | |
</div> | |
); | |
} | |
// return value of useSteps | |
const steps = { | |
steps: {}, | |
progress: {}, | |
previousButton: {}, | |
nextButton: {}, | |
state: {} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useSteps, useStep } from "reakit"; | |
function Step({ state, ...props }) { | |
const { step, state: stepState } = useStep(state); | |
return stepState.mounted && <div {...mergeProps(step, props)} />; | |
} | |
function StepsDynamic() { | |
const { steps, previousButton, nextButton, state } = useSteps({ current: 0 }); | |
const items = ["First", "Second", "Third"]; | |
return ( | |
<div {...steps}> | |
<button {...previousButton}>Previous</button> | |
<button {...nextButton}>Next</button> | |
{items.map(step => ( | |
<Step key={step} state={state}>{step}</Step> | |
))} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useTabList, useTab } from "reakit"; | |
function Tabs() { | |
// some modules have collections | |
// collections have their own state (e.g. useTabListState) | |
const { list, previousButton, nextButton, state } = useTabList({ current: 0 }); | |
// first = { tab, panel, state } | |
// state can be useTabState, useTabPanelState or useHiddenState | |
const first = useTab(state); | |
const second = useTab(state); | |
const third = useTab(state); | |
return ( | |
<div> | |
<ul {...list}> | |
<li><button {...previousButton}>Previous</button></li> | |
<li><button {...first.tab}>First</button></li> | |
<li><button {...second.tab}>Second</button></li> | |
<li><button {...third.tab}>Third</button></li> | |
<li><button {...nextButton}>Next</button></li> | |
</ul> | |
{first.state.mounted && <div {...first.panel}>First</div>} | |
{second.state.mounted && <div {...second.panel}>Second</div>} | |
{third.state.mounted && <div {...third.panel}>Third</div>} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { | |
useTabTab, | |
useTabPanel, | |
useTabListState, | |
useTabListList, | |
mergeProps | |
} from "reakit"; | |
function Tab({ state, ...props }) { | |
// useTabTab implements useTheme("Tab") underneath | |
const tab = useTabTab(state); | |
return <button {...mergeProps(tab, props)} />; | |
} | |
function Panel({ state, ...props }) { | |
// panel has its own state, which can be useTabState, useTabPanelState or useHiddenState | |
// and that's why it's a map | |
const { panel, state: panelState } = useTabPanel(state); | |
return {panelState.mounted && <div {...mergeProps(panel, props)} />}; | |
} | |
function TabsDynamic() { | |
// Decoupling state and tabs | |
// same as | |
// const { tabs, state } = useTabList({ current: 0 }) | |
const state = useTabListState({ current: 0 }); | |
const list = useTabListList(state); | |
const tabs = ["First", "Second", "Third"]; | |
return ( | |
<div> | |
<ul {...list}> | |
{tabs.map(tab => ( | |
<li key={tab}><Tab state={state}>{tab}</Tab></li> | |
))} | |
</ul> | |
{tabs.map(tab => ( | |
<Panel key={tab} state={state}>{tab}</Panel> | |
))} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useToolbar, useToolbarItem, mergeProps } from "reakit"; | |
function Toolbar() { | |
const { toolbar, state } = useToolbar({ orientation: "vertical" }); | |
const item1 = useToolbarItem(state); | |
const item2 = useToolbarItem(state); | |
return ( | |
<div {...toolbar}> | |
<button {...item1} /> | |
<button {...item2} /> | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useToolbar, useToolbarItem, mergeProps } from "reakit"; | |
function ToolbarItem({ state, as: T = "div", ...props }) { | |
const item = useToolbarItem(state); | |
return <T {...mergeProps(item, props)} />; | |
} | |
function ToolbarDynamic() { | |
const { toolbar, state } = useToolbar(); | |
const items = [{ as: MenuIcon }, { as: "img", src: "https://placekitten.com/150/200" }]; | |
return ( | |
<div {...toolbar}> | |
{items.map((props, i) => ( | |
<ToolbarItem key={i} state={state} {...props} /> | |
))} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useTooltip } from "reakit"; | |
function Tooltip() { | |
// useTooltip implements usePlugin("useTooltip") underneath | |
const { tooltip, arrow, reference, state } = useTooltip({ placement: "top" }); | |
return ( | |
<div> | |
<button {...reference}>Hover me</button> | |
{state.mounted && ( | |
<div {...tooltip}> | |
<div {...arrow} /> | |
Tooltip | |
</div> | |
)} | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment