I'm trying to make a Trello like, I'm using react-beautiful-dnd and started from the classical example.
This is where I render the card (I just replaced the div with Task, my component)
<Task
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
userSelect: "none",
padding: 16,
margin: "0 0 8px 0",
minHeight: "50px",
...provided.draggableProps.style,
}}
>
{item.content}
</Task>
In my component, I want to get all div attributes passed in the code above.
So I did this :
import React from "react";
const Task: React.FC<JSX.IntrinsicElements["div"]> = (props) => {
const { children } = props;
return (
<div className="card card-green" {...props}>
<div className="card-content">
<div className="content">{children}</div>
</div>
</div>
);
};
export default Task;
It looks good, excepted for the "ref", I got a message in my console when I try to drag my card
Invariant failed: Cannot get dimension when no ref is set
And indeed my ref is always undefined.
Do you have an idea ?
I tried several examples found but no one works. I think I am missing a type somewhere
Here is the video proof.
https://dsc.cloud/leonardchoo/Screen-Recording-2022-03-08-at-17.25.58.mov
I'm running into a mysterious error where I click the button for navigation, "onClick" event is fired but it does not redirect and render the target component.
As you can see in the screenshot, the onClick event is logged, but the redirect does not happen.
I reproduced the situation here in CodeSandbox.
Stack
React TS
Mantine UI
React Router V5
How can I solve this issue?
First thing I noticed in your code was that is is rendering a WrapperPage component around each routed component with the navigation logic. I tried simplifying the WrapperPage code as much as possible.
Steps Taken:
Refactored the header and navbar props into standalone components in case there was issue generating JSX
Wrapped the Switch component in App with a single WrapperPage instead of each routed component
The issue persisted.
I next removed the UnstyledButton from #mantine/core so only the Link components were rendered, and could not reproduce. I then tried vanilla HTML buttons instead of the UnstyledButton and they again reproduced the issue.
So it seems it is an issue with rendering an interactive element (i.e. anchor tag from Link) within another interactive element (i.e. button from UnstyledButton) that is an issue. Swapping the element order, i.e. Link wrapping the UnstyledButton, appears to reduce the issue. I can't seem to reproduce the issue with the DOM structured this way.
Header
const CustomHeader = ({
opened,
setOpened
}: {
opened: boolean;
setOpened: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const theme = useMantineTheme();
return (
<Header height={70} padding="md">
{/* Handle other responsive styles with MediaQuery component or createStyles function */}
<div style={{ display: "flex", alignItems: "center", height: "100%" }}>
<MediaQuery largerThan="sm" styles={{ display: "none" }}>
<Burger
opened={opened}
onClick={() => setOpened((o) => !o)}
size="sm"
color={theme.colors.gray[6]}
mr="xl"
/>
</MediaQuery>
<Group>
<ThemeIcon variant="light" color="orange">
🎙
</ThemeIcon>
<Text>Mantine AppShell with React Router</Text>
</Group>
</div>
</Header>
);
};
Navbar
const CustomNavbar = ({ opened }: { opened: boolean }) => {
const location = useLocation();
const { classes } = useStyles();
return (
<Navbar
padding="md"
// Breakpoint at which navbar will be hidden if hidden prop is true
hiddenBreakpoint="sm"
// Hides navbar when viewport size is less than value specified in hiddenBreakpoint
hidden={!opened}
// when viewport size is less than theme.breakpoints.sm navbar width is 100%
// viewport size > theme.breakpoints.sm – width is 300px
// viewport size > theme.breakpoints.lg – width is 400px
width={{ sm: 300, lg: 400 }}
>
<Link
to="/dashboard"
className={classes.link}
>
<UnstyledButton
className={
location.pathname === "/dashboard"
? classes.button_active
: classes.button
}
>
<Group>
<ThemeIcon variant="light">
<DashboardIcon />
</ThemeIcon>
<Text size="sm">Dashboard</Text>
</Group>
</UnstyledButton>
</Link>
<Link
to="/new-recording"
className={classes.link}
>
<UnstyledButton
className={
location.pathname === "/new-recording"
? classes.button_active
: classes.button
}
>
<Group>
<ThemeIcon variant="light" color="red">
<RadiobuttonIcon />
</ThemeIcon>
<Text size="sm">New Recording</Text>
</Group>
</UnstyledButton>
</Link>
<Link
to="/calendar"
className={classes.link}
>
<UnstyledButton
className={
location.pathname === "/calendar"
? classes.button_active
: classes.button
}
>
<Group>
<ThemeIcon variant="light" color="orange">
<CalendarIcon />
</ThemeIcon>
<Text size="sm">Calendar</Text>
</Group>
</UnstyledButton>
</Link>
</Navbar>
);
};
WrapperPage
const WrapperPage = ({ children }: Props): JSX.Element => {
const [opened, setOpened] = useState(false);
return (
<AppShell
// navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left
navbarOffsetBreakpoint="sm"
// fixed prop on AppShell will be automatically added to Header and Navbar
fixed
header={<CustomHeader opened={opened} setOpened={setOpened} />}
navbar={<CustomNavbar opened={opened} />}
>
{children}
</AppShell>
);
};
I have a functional component that is supposed to switch between the login view, and the Register view based on a hook state. React keeps passing the error: "Expected onClick listener to be a function, instead got a value of boolean type." even though I have worked on other components before the same way. Any help would be appreciated
const UserPane = () => {
const [newUser, setNewUser] = useState(false)
const toggleNewUser = () => setNewUser(!newUser)
return (
<>
<div className="container p-5 pb-2 mb-3">
{newUser ?
<Register /> :
<Login />
}
{newUser.toString()}
<a onClick={() => setNewUser(!newUser)} style={{ color: "#845ec2", cursor: "pointer" }} onClick>
Don't have an account? Click here to register
</a>
</div>
</>
)
}
You are seeing error because of the last onClick (scroll to end of the line)
<a onClick={() => setNewUser(!newUser)} style={{ color: "#845ec2", cursor: "pointer" }} onClick> //<---This
This last onClick essentially overwrites the previous onClick with onClick={true} which is not an acceptable onClick value
I hope, you are facing an issue with toggling the newUser.
To alter the state, you should use
setNewUser(prev => !prev)
I am trying to figure out how to style icons that I import using react-icons.
In particular, I would like to be able to create a look similar to this:
That is to say, I'd like to add a background color, padding, border-radius, etc. However, I can't find an easy way to do that.
I can add a size and color prop and that will change the actual size and color of the icon. But there is no easy way for me to change the other elements.
Does anyone know how I can do this (or can they recommend a different library that can help me with this)?
Use IconContext as mentioned in the Docs.
function BlueLargeIcon() {
return (
<IconContext.Provider
value={{ color: 'blue', size: '50px' }}
>
<div>
<FaBeer />
</div>
</IconContext.Provider>
);
}
To target specific Icon Components, you can use the style prop or use the same API (see Configurations) on the component itself:
const style = { color: "white", fontSize: "1.5em" }
<FaFacebookF style={style} />
// API
<FaFacebookF color="white" fontSize="1.5em" />
Colours of some icons can't be changed. For example, I tried to change the colour of { GrClose } icon by doing this:
<GrClose
className="icon"
style={{
position: 'absolute',
top: '20px',
right: '20px',
}}
size="50px"
color="white"
onClick={handleExit}
/>
It just didn't change, when I replaced my icon with { AiOutlineClose } icon it worked!
I think the easiest way here would be to just pass the className prop directly to the Icon you'd like to apply styles to. Source Code in a CodeSandbox. I've used tailwindcss classes here, but you could use your own just as easily.
import React from "react";
import "./styles.css";
import {
FaFacebookF,
FaTwitter,
FaInstagram,
FaPinterest
} from "react-icons/fa";
export default function App() {
let circleClasses = "inline-block p-7 rounded-full w-20 mx-auto";
let iconStyles = { color: "white", fontSize: "1.5em" };
return (
<div className="App grid grid-cols-2 sm:grid-cols-4 gap-2 w-3/4 mx-auto">
<h1 className="col-span-full">Icon Demo</h1>
<span style={{ background: "#3B5998" }} className={circleClasses}>
<FaFacebookF style={iconStyles} />
</span>
<span style={{ background: "#1DA1F2" }} className={circleClasses}>
<FaTwitter style={iconStyles} />
</span>
<span style={{ background: "black" }} className={circleClasses}>
<FaInstagram style={iconStyles} />
</span>
<span style={{ background: "#BD081C" }} className={circleClasses}>
<FaPinterest style={iconStyles} />
</span>
</div>
);
}
If you'd like a little more context as to how this works, we can take a dive into the source code for react-icons.
If you take a look at where the IconContext is defined within react-icons, you can see the allowed props:
export interface IconContext {
color?: string;
size?: string;
className?: string;
style?: React.CSSProperties;
attr?: React.SVGAttributes<SVGElement>;
}
export const DefaultContext: IconContext = {
color: undefined,
size: undefined,
className: undefined,
style: undefined,
attr: undefined,
};
export const IconContext: React.Context<IconContext> = React.createContext && React.createContext(DefaultContext);
Indeed, you're able to pass in color, size, style, additional svg attributes, and even a className string. But, this requires that you wrap the Icon component in the context.
When you install react-icons, all of the icons are added into the node_modules directory in a format that looks like this:
// THIS FILE IS AUTO GENERATED
var GenIcon = require('../lib').GenIcon
module.exports.Fa500Px = function Fa500Px (props) {
return GenIcon({"tag":"svg","attr":{"viewBox":"0 0 448 512"},"child":[{"tag":"path","attr":{"d":"M103.3 344.3c-6.5-14.2-6.9-18.3 7.4-23.1 25.6-8 8 9.2 43.2 49.2h.3v-93.9c1.2-50.2 44-92.2 97.7-92.2 53.9 0 97.7 43.5 97.7 96.8 0 63.4-60.8 113.2-128.5 93.3-10.5-4.2-2.1-31.7 8.5-28.6 53 0 89.4-10.1 89.4-64.4 0-61-77.1-89.6-116.9-44.6-23.5 26.4-17.6 42.1-17.6 157.6 50.7 31 118.3 22 160.4-20.1 24.8-24.8 38.5-58 38.5-93 0-35.2-13.8-68.2-38.8-93.3-24.8-24.8-57.8-38.5-93.3-38.5s-68.8 13.8-93.5 38.5c-.3.3-16 16.5-21.2 23.9l-.5.6c-3.3 4.7-6.3 9.1-20.1 6.1-6.9-1.7-14.3-5.8-14.3-11.8V20c0-5 3.9-10.5 10.5-10.5h241.3c8.3 0 8.3 11.6 8.3 15.1 0 3.9 0 15.1-8.3 15.1H130.3v132.9h.3c104.2-109.8 282.8-36 282.8 108.9 0 178.1-244.8 220.3-310.1 62.8zm63.3-260.8c-.5 4.2 4.6 24.5 14.6 20.6C306 56.6 384 144.5 390.6 144.5c4.8 0 22.8-15.3 14.3-22.8-93.2-89-234.5-57-238.3-38.2zM393 414.7C283 524.6 94 475.5 61 310.5c0-12.2-30.4-7.4-28.9 3.3 24 173.4 246 256.9 381.6 121.3 6.9-7.8-12.6-28.4-20.7-20.4zM213.6 306.6c0 4 4.3 7.3 5.5 8.5 3 3 6.1 4.4 8.5 4.4 3.8 0 2.6.2 22.3-19.5 19.6 19.3 19.1 19.5 22.3 19.5 5.4 0 18.5-10.4 10.7-18.2L265.6 284l18.2-18.2c6.3-6.8-10.1-21.8-16.2-15.7L249.7 268c-18.6-18.8-18.4-19.5-21.5-19.5-5 0-18 11.7-12.4 17.3L234 284c-18.1 17.9-20.4 19.2-20.4 22.6z"}}]})(props);
};
If we take a look at the source code for GenIcon we can get a bit more context for how this is working.
import * as React from 'react';
import { IconContext, DefaultContext } from './iconContext';
export interface IconTree {
tag: string;
attr: {[key: string]: string};
child: IconTree[];
}
function Tree2Element(tree: IconTree[]): React.ReactElement<{}>[] {
return tree && tree.map((node, i) => React.createElement(node.tag, {key: i, ...node.attr}, Tree2Element(node.child)));
}
export function GenIcon(data: IconTree) {
return (props: IconBaseProps) => (
<IconBase attr={{...data.attr}} {...props}>
{Tree2Element(data.child)}
</IconBase>
);
}
export interface IconBaseProps extends React.SVGAttributes<SVGElement> {
children?: React.ReactNode;
size?: string | number;
color?: string;
title?: string;
}
export type IconType = (props: IconBaseProps) => JSX.Element;
export function IconBase(props:IconBaseProps & { attr?: {} }): JSX.Element {
const elem = (conf: IconContext) => {
const {attr, size, title, ...svgProps} = props;
const computedSize = size || conf.size || "1em";
let className;
if (conf.className) className = conf.className;
if (props.className) className = (className ? className + ' ' : '') + props.className;
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
{...conf.attr}
{...attr}
{...svgProps}
className={className}
style={{ color: props.color || conf.color, ...conf.style, ...props.style}}
height={computedSize}
width={computedSize}
xmlns="http://www.w3.org/2000/svg"
>
{title && <title>{title}</title>}
{props.children}
</svg>
)
};
return IconContext !== undefined
? <IconContext.Consumer>{(conf: IconContext) => elem(conf)}</IconContext.Consumer>
: elem(DefaultContext);
}
So, GenIcon is a function that accepts an object with an interface of IconTree which includes tag, attr and child properties. We can see this in action in the generated code above. GenIcon returns a function itself. This function accepts props as an argument which implements the IconBaseProps interface. The IconBaseProps interface extends React.SVGAttributes which include className and style. Those are then passed as props to the IconBase component here:
export function GenIcon(data: IconTree) {
return (props: IconBaseProps) => (
<IconBase attr={{...data.attr}} {...props}>
{Tree2Element(data.child)}
</IconBase>
);
}
To get a sense of how IconBase actually works with respect to the IconContext let's check out its return statement:
return IconContext !== undefined
? <IconContext.Consumer>{(conf: IconContext) => elem(conf)}</IconContext.Consumer>
: elem(DefaultContext);
Here, we can see that IconBase will invoke a function called elem (defined inside the body of IconBase) either way. So, IconBase will use the IconContext if one is defined, wrapping the returned element in IconContext.Consumer and calling elem with the IconContext. But, if IconContext is not defined in this scope, IconBase will use the DefaultContext instead.
To understand how this is working, we need to look at the elem function defined inside of IconBase. Here's the full source again:
const elem = (conf: IconContext) => {
const {attr, size, title, ...svgProps} = props;
const computedSize = size || conf.size || "1em";
let className;
if (conf.className) className = conf.className;
if (props.className) className = (className ? className + ' ' : '') + props.className;
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
{...conf.attr}
{...attr}
{...svgProps}
className={className}
style={{ color: props.color || conf.color, ...conf.style, ...props.style}}
height={computedSize}
width={computedSize}
xmlns="http://www.w3.org/2000/svg"
>
{title && <title>{title}</title>}
{props.children}
</svg>
)
};
So, if you take a look at the code relating to className, you can see that we can actually add className to the Context and/or the props directly (<FaFacebook className="bg-blue" />) and they'll actually be combined and applied to the returned svg
let className;
if (conf.className) className = conf.className;
if (props.className) className = (className ? className + ' ' : '') + props.className;
Also, the styles defined in either the Context or the props will be combined and applied to the svg
style={{ color: props.color || conf.color, ...conf.style, ...props.style}}
One thing to note here is that all of the styles and classes are being applied directly to the returned svg element. So, in your case, you'd probably need to have a wrapping element to build out the border-radius and background color and then apply the relevant styles for color and size directly to the svg.
Simply add "color" property to
Like This:
<Icon color="blue" />
import {IconContext} from "react-icons";
class App extends component {
return (
<div>
<IconContext.Provider value={{ className="myReact-icons"}}>
<FaBeer />
</IconContext.Provider>
</div>
);
}
css example below
.myreact-icons { color: red;
height: 40px;
}
There is a simpler way to change the color of a react-icon.you can choose everything inside the svg icon with .icon > * use the css fill to fill the svg path.
```
.icon > * {
fill: #B3B3B3;
}
.icon > *:hover {
fill: #747474;
}
```
You can do it by simply adding colour property to icon, same goes for other properties like size.
<BiXCircle size={40} color="red" />
<HiOutlineInformationCircle
size= {40}
color="#777C92"
className = "m-1 cursor-pointer hover: stroke-[#E5765D]"
/>
Color changes on Grommet Icons don't apply. You can try with others either by passing a class and target it with css or directly inside <IconExample color={'blue'} />
function blackReactIcons () {
return(
<div>
<FaTwitter fill='#000' />
<FaLinkedinIn fill='#000' />
<FaGithub fill='#000' />
</div>
);
}
It is so easy just capsule your **icon** in **span tag**
<div className="social-icons">
<span>
<FaGithub/>
</span>
</div>
then style it using **CSS**
.social-icons span{
margin: 10px;
font-size: 20px;
color: var(--grey);
}
.social-icons span:hover{
color:black
}
You can export them as an object(s) with other properties and map through them.
import { FaInstagram, FaTwitter } from 'react-icons/fa';
export const socialIcons = [
{
icon: <FaInstagram
style={{ height: '30px', width: '30px' }}
/>,
title: 'Instagram',
link: '',
color: '#C13584',
isOpen: false,
id: 'instagram',
},
{
icon: <FaTwitter
style={{ height: '30px', width: '30px' }}/>,
title: 'Twitter',
link: '',
color: '#00acee',
isOpen: false,
id: 'twitter',
},
];
import { socialIcons } from '../';
// ...
<div>
{socialIcons.map((social) => (
<div>
<a href={social.link}>
<button style={{ color: social.color }}
id={social.id}>
{social.icon}
</button>
</a>
</div>
))}
</div>
In your styles.scss or css
.iconFaFacebook {
color: blue;
font-size: 2.5rem;
}
<FaFacebook className={styles.iconFaFacebook} />
Open the sidebar example in official docs of react router. You can see that ul is rendered without Route since it is supposed to be there on screen irrespective of the url. Open React DevTools, check Highlight updates checkbox and click on any of the menu items in the side bar. You will notice that elements under ul re-render on every click. In my opinion, it is not sane behavior, react elements under ul should not re-render with route change given they are not rendered by react routers Route component. Is there a way I can stop them re-rendering?
A Router component depends on context for the change and whenver a context value is updated, it triggers a re-render of the children to do a match and render the appropriate route. Now since the ul element is directly written as a child of Router, it also gets re-rendered. Although react performs a virtual-dom comparison and the DOM won't be re-rendered, you can avoid it by using a PureComponent and writing ul elements within that Component
const SidebarExample = () => (
<Router>
<div style={{ display: "flex" }}>
<div
style={{
padding: "10px",
width: "40%",
background: "#f0f0f0"
}}
>
<Route component={Elements}/>
{routes.map((route, index) => (
// You can render a <Route> in as many places
// as you want in your app. It will render along
// with any other <Route>s that also match the URL.
// So, a sidebar or breadcrumbs or anything else
// that requires you to render multiple things
// in multiple places at the same URL is nothing
// more than multiple <Route>s.
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.sidebar}
/>
))}
</div>
<div style={{ flex: 1, padding: "10px" }}>
{routes.map((route, index) => (
// Render more <Route>s with the same paths as
// above, but different components this time.
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.main}
/>
))}
</div>
</div>
</Router>
)
class Elements extends React.PureComponent {
render() {
return (
<ul style={{ listStyleType: "none", padding: 0 }}>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/bubblegum">Bubblegum</Link>
</li>
<li>
<Link to="/shoelaces">Shoelaces</Link>
</li>
</ul>
)
}
}