Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
react-interactive
Advanced tools
hover
, active
, focus
, etc... (no style tags or CSS added to the page), or use class names if you prefer to write styles separately with CSSactive
states for mouse, touch, and keyboard interactions (not possible with CSS)focus
states based on how it was entered - from mouse, touch, or tab key (not possible with CSS)Interactive
parent's state (only possible with complex CSS selectors)click
event is generated on mouse click, touch tap (without delay), and enter keydownimport Interactive from 'react-interactive';
...
<Interactive
as="div" // what the Interactive component is rendered as, can be anything
hover={{ color: 'green' }} // style object, can use any styles you'd like
active={{ color: 'blue' }}
// OR
hoverActive={{ color: 'red' }}
touchActive={{ color: 'blue' }}
keyActive={{ color: 'orange' }}
focus={{ outline: '2px solid green' }}
// OR
focusFromTab={{ outline: '2px solid orange' }}
focusFromMouse={{ outline: '2px solid green' }}
focusFromTouch={{ outline: '2px solid blue' }}
// hook called on every state change, receives prevState and nextState objects
onStateChange={this.handleInteractiveStateChange}
onClick={this.handleClick}
style={{ fontSize: '16px', padding: '3px', color: 'black' }}
>This is an interactive and focusable div</Interactive>
Interactive state machine as a React component. There are 5 mutually exclusive iStates, plus 3 mutually exclusive focus states that can be combined with the 5 iStates (the total number of states that RI can be in is 19, see State Machine Notes below).
normal
hover
hoverActive
touchActive
keyActive
focusFromTab
focusFromMouse
focusFromTouch
*The 3 separate [type]Active
states can be treated as a single active
state if desired. hoverActive
(mouse on and button down), touchActive
(touch on screen), keyActive
(has focus and enter key down).
**The 3 separate focusFrom[Type]
states can be treated as a single focus
state if desired.
Compared to CSS, React Interactive is a simpler state machine with better touch device and keyboard support, and state change hooks. See comparison below.
// Interactive div with state change hook
<Interactive
as="div"
normal={{ color: 'black' }}
hover={{ color: 'green' }}
active="hover" // use the hover state style for the active state
style={{ fontSize: '16px', padding: '3px', border: '2px dotted black' }}
onClick={this.handleClick}
onStateChange={this.handleInteractiveStateChange}
>This is an interactive div with state change hook</Interactive>
// Interactive as a React Router Link component
import { Link } from 'react-router-dom';
...
<Interactive
as={Link}
to="/some/path"
hover={{ color: 'green' }}
active={{ color: 'blue' }}
style={{ color: 'black', padding: '3px' }}
>This is an interactive React Router Link component</Interactive>
// Interactive link with separate styles for mouse, touch, and keyboard interactions
<Interactive
as="a"
href="https://example.tld"
normal={{ color: 'black' }}
// mouse interactions: normal -> hover -> hoverActive
hover={{ color: 'green' }}
hoverActive={{ color: 'red' }}
// touch interactions: normal -> touchActive
touchActive={{ color: 'blue' }}
// keyboard interactions: normal -> normal with focusFromTab -> keyActive with focusFromTab
focusFromTab={{ outline: '2px solid orange' }}
keyActive={{ color: 'orange' }}
>This is an interactive link with separate styles for each type of interaction</Interactive>
// Interactive div with class names instead of styles
<Interactive
as="div"
hover={{ className: 'hover-class' }}
hoverActive={{ className: 'hover-active-class' }}
touchActive={{ className: 'touch-active-class' }}
keyActive={{ className: 'key-active-class' }}
// use focusFromTab to only apply the class when focus comes from the keyboard
focusFromTab={{ className: 'tab-focus-class' }}
className="some-class"
>This is an interactive div with classes instead of inline styles</Interactive>
react-interactive
$ yarn add react-interactive
# OR
$ npm install --save react-interactive
import Interactive from 'react-interactive';
// OR
var Interactive = require('react-interactive');
Or use the UMD build that's available on Unpkg (the component will be available to use as Interactive
)
<script src="https://unpkg.com/react-interactive/dist/ReactInteractive.min.js"></script>
<Interactive />
Note that there are no default values for any prop, and the only required prop is as
.
For the definition of when each state is entered, see the state machine definition below.
Prop | Type | Example | Description |
---|---|---|---|
as | string (html tag name) or ReactComponent or JSX/ReactElement | "div" or MyComponent or <div>...</div> <MyComponent /> | What the Interactive component is rendered as. It can be an html tag name (as a string), or it can be a ReactComponent (RI's callbacks are passed down as props to the component), or it can be a JSX/ReactElement (see as prop type notes for more info). Note that as is hot-swappable on each render and RI will seamlessly maintain the current interactive state. The as prop is required (it is the only required prop). |
normal | style object or options object or string | { color: 'black' } or { style: { color: 'black' }, className: 'some-class' } or 'hover' | Style or options object for the normal state, or a string indicating a state to match. If it's an object, it can be either a style object or an options object with the keys style and className . The style object is merged with both the style prop and the focus state style (see merging styles for the order that styles are merged in). The className is a string of space separated class names and is merged as a union with the className prop and the focus state className . If the value of the normal prop is a string, it must indicate one of the other states, e.g. 'hover' , and that state's style and className properties will be used for both states. |
hover | style object or options object or string | { color: 'green' } or... (same as above) | Same as normal , but for the hover state. Note that if there is no hoverActive or active prop, then the hover prop's style and classes are used for the hoverActive state. This state is entered when the mouse is on the RI element. |
active | style object or options object or string | { color: 'red' } or... (same as above) | Same as normal , but for the active state. Note that the active state is the union of the hoverActive , touchActive , and keyActive states. The active prop is only used in place of the [type]Active prop if the respective [type]Active prop is not present. |
hoverActive | style object or options object or string | { color: 'red' } or... (same as above) | Same as normal , but for the hoverActive state. Note that if there is no hoverActive or active prop, then the hover prop's style and classes are used for the hoverActive state. This state is entered when the mouse is on the RI element and the mouse button is down. |
touchActive | style object or options object or string | { color: 'blue' } or... (same as above) | Same as normal , but for the touchActive state. This state is entered when a touch point is on the RI element. |
keyActive | style object or options object or string | { color: 'yellow' } or... (same as above) | Same as normal , but for the keyActive state. This state is entered when the RI element has focus and the enter key is down. |
focus | style object or options object or string | { outline: '2px solid green' } or... (same as above) | Same as normal , but for the focus state. Note that the focus state is the union of the focusFromTab , focusFromTouch , and focusFromMouse states. The focus prop is only used in place of the focusFrom[Type] prop if the respective focusFrom[Type] prop is not present. |
focusFromTab | style object or options object or string | { outline: '2px solid green' } or... (same as above) | Same as normal , but for the focusFromTab state. This state is entered if focus is from the tab key (i.e. tabbing through the focusable elements on the page). Also, any focus calls not from a mouse or touch interaction (e.g. from assistive tech) will match with focusFromTab . |
focusFromMouse | style object or options object or string | { outline: '2px solid red' } or... (same as above) | Same as normal , but for the focusFromMouse state. This state is entered when focus is from a mouse interaction. |
focusFromTouch | style object or options object or string | { outline: '2px solid blue' } or... (same as above) | Same as normal , but for the focusFromTouch state. This state is entered when focus is from a touch interaction. |
style | style object | { margin: '10px' } | Styles that are always applied. Styles are merged with state styles. State styles have priority when there are conflicts. |
className | string | "some-class other-class" | Classes that are always applied to the element, and are merged as a union with state classes. |
onStateChange | function | function({ prevState, nextState, event }) {...} | Function called on each state change. Receives an object with prevState , nextState and event keys as the sole argument. prevState and nextState are state objects. The event is the event that caused the state change (a synthetic React event). |
setStateCallback | function | function({ prevState, nextState }) {...} | Function passed in as a callback when RI calls setState . Receives the same object as onStateChange as its sole argument, except without the event key (setState is asynchronous and React events don't persist asynchronously). Use this hook if you need to wait until the DOM is updated before executing the callback. |
onClick | function | function(event, clickType) {...} Where clickType is one of: 'mouseClick' 'tapClick' 'keyClick' | Function called for mouse clicks, touch taps with 1 touch point/finger (called without delay), enter keydown events (if the element has focus), and synthetic click events. The event argument will always be a click event (node.click() is called to generate a click event if needed). The clickType argument will always be one of mouseClick , tapClick , or keyClick . It will be mouseClick for mouse clicks and for synthetic click events on mouse only and hybrid devices. It will be tapClick for touch taps with 1 touch point and for synthetic click events on touch only devices. It will be keyClick if the click event was generated from a enter keydown event (or, for some elements, a space keyup event). Note that RI will call node.click() for enter keydown events only if there is an onClick prop. |
onTapTwo | function | function(event) {...} | Function called for taps with 2 touch points, e.g. a 2 finger tap. Event passed in is the touchend event from last touch point to leave the surface. |
tapTimeCutoff | whole number | 500 | Number of ms to allow for a tap. This is the cutoff time that separates a tap from a long press. This prop is not required and the default is 500 . |
onLongPress | function | function(event) {...} | Function called on long press if touch is present after the tapTimeCutoff and if the touch has not moved more than is allowed for a tap . Event passed in is the touch start event that started the long press. |
touchActiveTapOnly | boolean | touchActiveTapOnly | Add this prop to only remain in the touchActive state while a tap is possible. If the touch is moved more than the tolerance for a tap, or held on the screen longer than the time allowed for a tap, then the touchActive state is exited. This is useful when the intention of the touchActive state is to indicate to the user that they are tapping something. Note that without this prop React Interactive will remain in the touchActive state as long as the touch point is on the screen. |
extraTouchNoTap | boolean | extraTouchNoTap | Add this prop to cancel taps while touching someplace else on the screen. By default RI will ignore extra touches on the screen and allow taps on the RI element regardless of other touches. |
nonContainedChild | boolean | nonContainedChild | Add this prop if the DOM node's children are not contained inside of it on the page. For example, a child that is absolutely positioned outside of its parent. React Interactive does some quality control checks using node.getBoundingClientRect() , and by default the children are assumed to be within the parent's rectangle, but if this is not the case, then add this prop and the children will be checked. |
initialState | state object | { iState: 'normal', focus: 'tab' } | Optional initial state to enter when the component is mounted. A state object with keys for one or both of iState and focus . Note that for an active iState , you must specify [type]Active and not just active . Used in the constructor to set iState and in componentDidMount to set focus (RI can't set focus until after it has a reference to the DOM node). |
forceState | state object | { iState: 'normal', focus: false } | Force enter this state. Same as initialState except not used for the initial render. Note that if only one key is present, a shallow merge is done with the current state, for example, use { focus: 'tab' } to only focus the element. Only used in componentWillReceiveProps . |
stylePriority | object | { hover: true, hoverActive: true } | By default the focus state style takes precedence over the iState style when merged (except for the keyActive iState). Use this prop to specify specific iStates whose style should take precedence over the focus state style. Note that for an active iState , you must specify [type]Active and not just active . |
refDOMNode | function | function(node) {...} | Function is passed in a reference to the DOM node, and is called whenever the node changes. You shouldn't need to use this for anything related to React Interactive, but it's available in case you need to use it for other things. Note that if you need to focus/blur the DOM node, use the forceState or initialState prop and set the focus state instead of calling focus/blur directly on the DOM node. |
focusToggleOff | boolean | focusToggleOff | Add this prop to prevent focus from toggling on mouseup/tap. With this prop RI will enter the focus state normally and will remain in the focus state until the browser sends a blur event. |
mutableProps | boolean | mutableProps | Add this prop if you are passing in mutable props so the component will always update. By default it's assumed that props passed in are immutable. A shallow compare is done, and if the props are the same, the component will not update. If you're not sure and notice buggy behavior, then add this prop. |
interactiveChild | boolean | interactiveChild | Add this prop if Interactive's children use the Interactive Children API. |
wrapperStyle | style object | { display: 'block' } | Styles that are applied to the span wrapper if as is a ReactComponent. |
wrapperClassName | string | "ri-wrapper-class other-class" | Classes that are applied to the span wrapper if as is a ReactComponent. |
... | anything | id="some-id" , tabIndex="1" , etc... | All additional props received are passed through. |
style
propkeyActive
)keyActive
state stylestylePriority
prop and specify which iStates should have priority over focus, e.g. stylePriority={{ hover: true, hoverActive: true }}
className
propas
Prop Typeas
is a string:
as="div"
div
, span
, a
, h1
, p
, ul
, li
, input
, select
, etc...as="svg"
works fine except that in general SVGs are not focusable by the browser, so if you need focus
then wrap the svg
element in a Interactive span
. Also with SVGs you can make a specific path interactive, e.g. as="path"
to create interactions within the SVG.as
is a ReactComponent:
as={MyComponent}
as
is either a ReactClass or a ReactFunctionalComponent as defined in the React Glossary.as
a ReactComponent, the component must pass down the props it receives from React Interactive to the top DOM node that it renders, and it cannot override any of the passed down event handlers, e.g. onMouseEnter
. Also, the component cannot replace its top DOM node once it's rendered unless the replacement is the result of new props (note that mutations are okay, e.g. changing style, classes, children, etc is fine). This is because React Interactive keeps a reference to the component's top DOM node so it can do things like call focus()
, and if the top DOM node is replaced without React Interactive's knowledge, then things start to break. Note that React Router's Link component meets these requirements.as
is a ReactComponent it is wrapped in a <span>
in order for React Interactive to maintain a reference to the top DOM node without breaking encapsulation. Without the span wrapper the only way to access the top DOM node would be through using ReactDOM.findDOMNode(component)
, which breaks encapsulation and is discouraged, and also doesn't work with stateless functional components.
<span>
wrapper can be styled by passing down the props wrapperClassName
(class string) and wrapperStyle
(style object).as
is a JSX/ReactElement:
as={<div>...</div>}
or as={<MyComponent />}
const jsxElement = <div hover={{ color: 'blue' }}>Some jsxElement text</div>;
<Interactive
as={jsxElement}
hover={{ color: 'green' }}
active={{ color: 'red' }}
>Some other text</Interactive>
div
with text that reads 'Some jsxElement text' and will be blue on hover and red on active. When the props are merged, jsxElement
's hover
prop and children
have priority over Interactive
's hover
prop and children
, but since jsxElement
didn't specify an active
prop, Interactive
's active
prop is still valid.as
is processed - either like a string or like a ReactComponent.as
is a ReactElement you cannot attach a ref
to it (only the Interactive
element is rendered and you can attach a ref
to Interactive
(or use the refDOMNode
prop), but it is not possible to have two ref
s to the same element).as
. For a more practical example see, Hot Swappable as
.state
Object// this.state
{
// iState is always 1 of 5 strings
iState: 'normal' / 'hover' / 'hoverActive' / 'touchActive' / 'keyActive',
// focus is always 1 or 4 values
focus: false / 'tab' / 'mouse' / 'touch',
}
onStateChange
and setStateCallback
hooks receive the previous and next state objects when they are called, and the forceState
and initialState
props pass in a state object to the RI component.role
and tabIndex
onClick
prop without a role
prop, and it's not clear what the role of the element is (i.e. it's not for user input, a link, or an area tag), then RI will automatically add role="button"
for better accessibility. If you don't want any role
added to the DOM element, then pass in the prop role={null}
.focus
or onClick
prop without a tabIndex
prop, then a tabIndex
of 0
is added to make the element focusable by the browser. If you don't want any tabIndex
added to the DOM element, then pass in the prop tabIndex={null}
.as="button"
is discouraged because browsers are inconsistent in how they display and handle button interactions. For better consistency, use as="div"/"span"
and add an onClick
handler. By default RI will add role="button"
, tabIndex="0"
, and a key click handler (which will call onClick
), so it will work just like a button. You can override these with your own role
and tabIndex
if you prefer.focusFrom
are implemented by controlling the browser's focus state.input
, textarea
, or select
.focusToggleOff
prop. With this prop RI will enter the focus state normally and will remain in the focus state until the browser sends a blur event.setState
call as the iState change, so the onStateChange
hook is only called once. For example, onMouseDown
enters the focus
state and the hoverActive
state in a single state change (and render). This achieved by controlling the browser's focus state - without this control the browser would fire the focus event immediately after the mouse down event resulting in two setState
calls (and two onStateChange
calls), one to enter the hoverActive
state and one to enter the focus
state.focus
prop is passed to React Interactive, then RI will prevent the browser's default focus outline from being applied.useBrowserOutlineFocus
useBrowserCursor
touchActive
or active
prop is passed to React Interactive, then RI will prevent the browser's default webkit tap highlight color from being applied.
WebkitTapHighlightColor
for styling, don't provide a touchActive
or active
prop and set the WebkitTapHighlightColor
style in the main style
prop.WebkitTapHighlightColor
is active to what results in a click. RI won't call node.click()
, so there may be a delay in the click event in some browsers.interactiveChild
prop to <Interactive />
to use the Interactive Children API (by default RI will not inspect its children and will render them as is).Interactive
components, the children will be styled based on the state of their closest Interactive
parent.function InteractiveChild() {
return (
<Interactive
as="ul"
interactiveChild // so Interactive will style the children based on its state
focusFromTab={{}} // so the Interactive component is focusable
touchActive={{}} // so Interactive will control taps and remove the browser's default style
>
<li>This list item will not change style based on the state of the Interactive parent.</li>
<li
onParentHover={{ color: 'green' }}
onParentHoverActive="hover" // use the onParentHover style for onParentHoverActive
onParentTouchActive={{ color: 'blue' }}
onParentFocusFromTab={{ outline: '2px solid green' }}
>
This list item will change style based on the state of the Interactive parent.
</li>
<li
showOnParent="hover hoverActive touchActive focusFromTab"
>
This list item is only rendered when the Interactive parent is in the
hover, hoverActive, touchActive or focusFromTab states.
</li>
</Interactive>
);
}
Prop | Type | Example | Description |
---|---|---|---|
showOnParent | space separated string | 'hover touchActive focusFromTab' | Add this props to only render the child when the parent is in any of the listed states. Without this prop, RI will always render the child. The acceptable state values are: hover , active (union of the 3 [type]Active states), hoverActive , touchActive , keyActive , focus (union of the 3 focusFrom[Type] states), focusFromTab , focusFromMouse , and focusFromTouch . List as a space separated string. |
onParentNormal | style object or options object or string | { color: 'black' } or { style: { color: 'black' }, className: 'some-class' } or 'hover' | Style or options object when the parent is in the normal state, or a string indicating a state to match. If it's an object, it can be either a style object or an options object with the keys style and className . The style object is merged with both the child's style prop and the onParentFocusFrom[Type] style in the same order as the Interactive parent. The className is a string of space separated class names and is merged as a union with the child's className prop and the onParentFocusFrom[Type] className . If the value of the onParentNormal prop is a string, it must indicate one of the other states, e.g. 'hover' (without the onParent prefix), and that state's onParent[State] style and className properties will be used for both states. Note that the interface is the same as <Interactive /> 's normal prop. |
onParentHover | style object or options object or string | { color: 'green' } or... (same as above) | Same as onParentNormal , but for the parent's hover state. Note that if there is no onParentHoverActive or onParentActive prop, then the onParentHover prop's style and classes are used for the onParentHoverActive prop. |
onParentActive | style object or options object or string | { color: 'red' } or... (same as above) | Same as onParentNormal , but for the parent's active state. Note that the onParentActive prop is only used in place of the onParent[Type]Active prop if the respective onParent[Type]Active prop is not present. |
onParentHoverActive | style object or options object or string | { color: 'red' } or... (same as above) | Same as onParentNormal , but for the parent's hoverActive state. Note that if there is no onParentHoverActive or onParentActive prop, then the onParentHover prop's style and classes are used for the onParentHoverActive prop. |
onParentTouchActive | style object or options object or string | { color: 'blue' } or... (same as above) | Same as onParentNormal , but for the parent's touchActive state. |
onParentKeyActive | style object or options object or string | { color: 'yellow' } or... (same as above) | Same as onParentNormal , but for the parent's keyActive state. |
onParentFocus | style object or options object or string | { outline: '2px solid green' } or... (same as above) | Same as onParentNormal , but for the parent's focus state. Note that the onParentFocus prop is only used in place of the onParentFocusFrom[Type] prop if the respective onParentFocusFrom[Type] prop is not present. |
onParentFocusFromTab | style object or options object or string | { outline: '2px solid green' } or... (same as above) | Same as onParentNormal , but for the parent's focusFromTab state. |
onParentFocusFromMouse | style object or options object or string | { outline: '2px solid red' } or... (same as above) | Same as onParentNormal , but for the parent's focusFromMouse state. |
onParentFocusFromTouch | style object or options object or string | { outline: '2px solid blue' } or... (same as above) | Same as onParentNormal , but for the parent's focusFromTouch state. |
Compared to CSS, React Interactive is a simpler state machine, with better touch device and keyboard support, and state change hooks.
mouseOn
: the mouse is on the elementbuttonDown
: the mouse button is down while the mouse is on the elementtouchDown
: at least one touch point is in contact with the screen and started on the elementfocusKeyDown
:
foucsKeyDown
state for the purposes of this abstraction), but is not consistent across browsers. Note that even though the enter key triggers links and buttons, pressing the enter key won't cause an element to enter the active state, which means that with CSS there is no way to give visual feedback when triggering an element with the enter key.Interactive state | Mouse, touch and keyboard states |
---|---|
base styles | Not an interactive state, always applied, everything merges with them |
normal | !mouseOn && !buttonDown && !touchDown && !focusKeyDown |
hover | mouseOn && !buttonDown && !touchDown && !focusKeyDown |
active | hoverActive OR keyActive OR touchActive |
hoverActive | mouseOn && buttonDown && !touchDown && !focusKeyDown |
keyActive | focusKeyDown && !touchDown |
touchActive | touchDown |
The three focusFrom
states can be combined with any of the above states, and the keyActive
state is only available while in the focus state.
Note that since a state machine can only be in one state at a time, to view interactive CSS as a state machine it has to be thought of as a combination of pseudo class selectors that match based on the mouse, keyboard and touch states.
Interactive state | Note | Mouse, touch and keyboard states | CSS Selector(s) |
---|---|---|---|
base styles | Always applied, everything merges with them | Not an interactive state | .class |
normal | Not commonly used in CSS (zeroing out/overriding base styles is used instead) | !mouseOn && !buttonDown && !touchDown && !focusKeyDown | .class:not(:hover):not(:active) |
hover | Only hover styles applied | (mouseOn && !buttonDown && !focusKeyDown) OR (after touchDown and sticks until you tap someplace else) - the sticky hover CSS bug on touch devices | .class:hover |
hoverActive | Both hover and active styles applied | (mouseOn && buttonDown) OR (mouseOn && focusKeyDown) OR (touchDown, but not consistent across browsers) | .class:hover , .class:active |
active | Only active styles applied | (buttonDown && !mouseOn currently, but had mouseOn when buttonDown started) OR (focusKeyDown && !mouseOn) OR (touchDown but not on the element currently, but not consistent across browsers) | .class:active |
The focus state can be combined with any of the above CSS interactive states to double the total number of states that the CSS interactive state machine can be in.
Note that you could achieve mutually exclusive hover and active states if you apply hover styles with the .class:hover:not(:active)
selector, and there are other states that you could generate if you wanted to using CSS selectors. You could also create a touch active state by using Current Input, so CSS has some flexibility, but it comes at the cost of simplicity, and in CSS touch and keyboard interactions are not well supported.
normal
, hover
, hoverActive
, touchActive
, and keyActive
. These are combined with 4 mutually exclusive and comprehensive focus states: false
, tab
, mouse
, and touch
, with the exception of keyActive
, which is only available while focus is not false
, for a total of 19 states:normal | hover | hoverActive | touchActive | N/A |
---|---|---|---|---|
normal with focusFromTab | hover with focusFromTab | hoverActive with focusFromTab | touchActive with focusFromTab | keyActive with focusFromTab |
normal with focusFromMouse | hover with focusFromMouse | hoverActive with focusFromMouse | touchActive with focusFromMouse | keyActive with focusFromMouse |
normal with focusFromTouch | hover with focusFromTouch | hoverActive with focusFromTouch | touchActive with focusFromTouch | keyActive with focusFromTouch |
onStateChange
hook is called each time a transition occurs between any of the 19 states. Note that a transition will never occur between two focusFrom
states as focusFrom
is based on how the focus state was entered, so have to transition to focus false
before transitioning to a different focusFrom
state.active
prop is just a convenience wrapper around the 3 specific active states: hoverActive
, touchActive
, and keyActive
, and is not a state in its own right.focus
prop is just a convenience wrapper around the 3 focusFrom
states: tab
, mouse
and touch
, and is not a state in its own right.import React from 'react';
import Interactive from 'react-interactive';
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
iState: 'normal',
focus: false,
};
}
handleOnStateChange = ({ nextState }) => {
this.setState(nextState);
// equivalent to the line above:
// this.setState({
// iState: nextState.iState,
// focus: nextState.focus,
// });
}
render() {
return (
<div>
<Interactive
as="div"
onStateChange={this.handleOnStateChange}
// ...and any other props as needed
>RI component</Interactive>
{
// create your component using:
// this.state.iState === 'normal' / 'hover' / 'hoverActive' / 'touchActive' / 'keyActive'
// this.state.focus === false / 'tab' / 'mouse' / 'touch'
}
</div>
);
}
}
handleOnStateChange
logic would apply when creating a ReactClass.import React from 'react';
import Interactive from 'react-interactive';
function MyFunctionalComponent() {
function enterFocus() {
// do something when enter the focus state
}
function leaveFocus() {
// do something when leave the focus state
}
function enterTouchActive() {
// do something when enter the touchActive state
}
function leaveTouchActive() {
// do something when leave the touchActive state
}
function handleOnStateChange({ prevState, nextState }) {
!prevState.focus && nextState.focus && enterFocus();
prevState.focus && !nextState.focus && leaveFocus();
if (nextState.iState === 'touchActive' && prevState.iState !== nextState.iState) {
enterTouchActive();
} else if (prevState.iState === 'touchActive' && prevState.iState !== nextState.iState) {
leaveTouchActive();
}
}
return (
<Interactive
as="div"
onStateChange={handleOnStateChange}
// ...and any other props as needed
>RI component</Interactive>
);
}
hover
and active
hover
or hoverActive
state.active
state, one of hoverActive
, touchActive
, or keyActive
.hoverActive
state.import React from 'react';
import Interactive from 'react-interactive';
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
hover: false,
active: false,
};
}
handleOnStateChange = ({ nextState }) => {
this.setState({
// hover and hoverActive both contain hover, so check nextState for hover
hover: /hover/.test(nextState.iState),
// hoverActive, touchActive, and keyActive all contain Active, note the capitalization
active: /Active/.test(nextState.iState),
});
}
render() {
return (
<div>
<Interactive
as="div"
onStateChange={this.handleOnStateChange}
// ...and any other props as needed
>RI element</Interactive>
{this.state.hover && <div>Div1 shown if RI is in the hover or hoverActive state</div>}
{this.state.active && <div>Div2 shown if RI is in one of the active states</div>}
</div>
);
}
}
hover
, touchActive
and focusFromTab
import React from 'react';
import Interactive from 'react-interactive';
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
showInfo: false,
};
}
shouldComponentUpdate(nextProps, nextState) {
return this.state.showInfo !== nextState.showInfo;
}
handleOnStateChange = ({ nextState }) => {
this.setState({
showInfo:
nextState.iState === 'hover' ||
nextState.iState === 'touchActive' ||
nextState.focus === 'tab'
});
}
render() {
return (
<div>
{this.state.showInfo && <div>Some info about something</div>}
<Interactive
as="div"
onStateChange={this.handleOnStateChange}
// ...and any other props as needed
>Show info</Interactive>
</div>
);
}
}
as
onClick
prop is only present on the clickToLoad
JSX element and not on the currentlyLoading
element, so any clicks that come through while loading will be ignored.import React, { PropTypes } from 'react';
import Interactive from 'react-interactive';
class MyComponent extends React.Component {
static propTypes = {
load: PropTypes.func.isRequired,
}
constructor() {
super();
this.state = {
loading: false,
};
}
loadSomething = () => {
this.setState({ loading: true });
this.props.load(() => {
this.setState({ loading: false });
});
}
render() {
const clickToLoad = (
<span
onClick={this.loadSomething}
hover={{ color: 'green' }}
active={{ color: 'blue' }}
focusFromTab={{ outline: '2px solid green' }}
>Load Something</span>
);
const currentlyLoading = (
<span
hover={{ color: 'gray' }}
active={{ color: 'lightgray' }}
focusFromTab={{ outline: '2px solid gray' }}
>Loading...</span>
);
return (
<Interactive
as={this.state.loading ? currentlyLoading : clickToLoad}
style={{ fontSize: '14px', padding: '5px' }}
normal={{ color: 'black' }}
/>
);
}
}
FAQs
Better hover, active and focus states than CSS pseudo-classes, and a callback when the interactive state changes.
The npm package react-interactive receives a total of 17,726 weekly downloads. As such, react-interactive popularity was classified as popular.
We found that react-interactive demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.