React-sortable-hoc: helperClass and styled-components

Created on 2 Jul 2018  ·  9Comments  ·  Source: clauderic/react-sortable-hoc

While using react-sortable-hoc I have to import a .css file with only a class to be passed to the helperClass prop in an otherwise css-file-free project using styled-components. In the API I couldn't find if a draggable element is dynamically assigned a prop (like isDragging or something similar) which I could use to dynamically update css.

Any suggestion on how I could avoid importing that .css file?

Most helpful comment

@JRMaitre Thank you for chiming in! I must have been trying to apply it to the container... when applied to the actual List Element in SortableElement, it works! Not sure what I was thinking.

Just for anyone else here is the full example based on the example in the Readme.

import React, {Component} from 'react';
import {render} from 'react-dom';
import {SortableContainer, SortableElement} from 'react-sortable-hoc';
import arrayMove from 'array-move';
import styled from 'styled-components'

const ListElement = styled.div`
  background-color: white;

  &.dragging-helper-class {
    box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.25);
  }
`

const SortableItem = SortableElement(({value}) => <ListElement>{value}</ListElement>);

const SortableList = SortableContainer(({items}) => {
  return (
    <ul>
      {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
      ))}
    </ul>
  );
});

class SortableComponent extends Component {
  state = {
    items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6'],
  };
  onSortEnd = ({oldIndex, newIndex}) => {
    this.setState(({items}) => ({
      items: arrayMove(items, oldIndex, newIndex),
    }));
  };
  render() {
    return <SortableList items={this.state.items} onSortEnd={this.onSortEnd} />;
  }
}

render(<SortableComponent />, document.getElementById('root'));

All 9 comments

One work-around I've used to make this work is that I use the helper class in the Styled Component itself.

const ListElement = styled.div
background-color: white;
&.dragging-helper-class {
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.25);
}

Thank you, that was exactly it.

FYI, I don't think this works anymore. See the image, looks like the Dragged List Item is rendered at the React app root and outside the sortable list. So, this method only applies the class name to a child of ListItem. I may be missing something...

screen shot 2019-01-29 at 11 18 22 pm

I was looking for this solution, because I'm using a theming system with styled components, so it would be nice to be able to set the style based on the theme and not have to import a single CSS file just for this.

I'm having the same problem, I need to apply a class on the element being dragged. Any solution?

@cmateusmoraes

The suggestion by @JRMaitre no longer works. I couldn't add more specificity in a styled-component, like he suggested because it is no longer rendered in the same parent container. I eventually just imported the css file, with a css class, which I was trying to avoid.

SortableComponent.js

import './SortableComponent.css'
...
              <SortableList
                renderItem={this.props.renderItem} 
                items={this.state.items} 
                onSortEnd={this.onSortEnd} 
                lockAxis="y"
                helperClass="dragging-helper-class"
                shouldCancelStart={ () => this.props.lock ? true : false}
                disableAutoscroll={false}
                useWindowAsScrollContainer={true}
                pressDelay={ size==='small' ? 100 : 0}
              />

SortableComponent.css

.dragging-helper-class div {
  font-family: Helvetica Neue, Helvetica, sans-serif;
  background-color: white;
}

.dragging-helper-class .shadow{
  box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.25);
}

.dragging-helper-class {
  list-style: none; 
}

It's a bummer, but was the fastest way to get around it for now.

In my case it still works, it doesn't matter that it's rendered outside of the parent because the styling is only applied to the ListElement which is a styled componentelement being dragged outside of the container. It's not scoped to only work in the container.

in this example

const ListElement = styled.div`
  background-color: white;

  &.dragging-helper-class {
    box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.25);
 }
`

List Element is the styled component representing the element being dragged. If &.dragging-helper-class (it has the class dragging helper class) then it adds some styling to it.

@JRMaitre Thank you for chiming in! I must have been trying to apply it to the container... when applied to the actual List Element in SortableElement, it works! Not sure what I was thinking.

Just for anyone else here is the full example based on the example in the Readme.

import React, {Component} from 'react';
import {render} from 'react-dom';
import {SortableContainer, SortableElement} from 'react-sortable-hoc';
import arrayMove from 'array-move';
import styled from 'styled-components'

const ListElement = styled.div`
  background-color: white;

  &.dragging-helper-class {
    box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.25);
  }
`

const SortableItem = SortableElement(({value}) => <ListElement>{value}</ListElement>);

const SortableList = SortableContainer(({items}) => {
  return (
    <ul>
      {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
      ))}
    </ul>
  );
});

class SortableComponent extends Component {
  state = {
    items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6'],
  };
  onSortEnd = ({oldIndex, newIndex}) => {
    this.setState(({items}) => ({
      items: arrayMove(items, oldIndex, newIndex),
    }));
  };
  render() {
    return <SortableList items={this.state.items} onSortEnd={this.onSortEnd} />;
  }
}

render(<SortableComponent />, document.getElementById('root'));

I was applying helperClass on the "SortableItem". Tks!

It's also worthy to note that, as pointed by @justdanallen's screenshot, the helper element (the one you see while dragging) is a child of <body>, regardless of where your SortableItem is. Therefore, in your CSS selector, do not treat your helper class as if it was a sibling of your SortableItems.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TriStarGod picture TriStarGod  ·  17Comments

mccambridge picture mccambridge  ·  10Comments

stahlmanDesign picture stahlmanDesign  ·  12Comments

sahilchaddha picture sahilchaddha  ·  16Comments

slmgc picture slmgc  ·  21Comments