How to Style <Link> using styled-component - javascript

I was using this Link from #material-ui/core/Link in my TypeScript code and it worked perfectly:
<Link href="#" variant="body2">
Forgot?
</Link>
However, I am trying to switch to styled-components placed in another file. Now, I am trying to use this (eg: https://styled-components.com/docs/basics):
const Link = ({ className, children}) => (
<a className={className}>
{children}
</a>
);
export const StyledLink = styled(Link)`
href: #;
variant: body2;
`;
along with:
<StyledLink>Forgot?</StyledLink>
But I keep getting errors on className and children that Binding element 'children' implicitly has an 'any' type.ts(7031but even if I add any, It doesn't work.
What is the correct way to use styled-components in this case? Or any other css-in-js alternative?

This code works, and gets no warnings from the typescript compiler
import styled from "styled-components";
const Link = ({
className,
children
}: {
readonly className: string;
readonly children: React.ReactElement;
}) => (
<a href="/" className={className}>
{children}
</a>
);
export const StyledLink = styled(Link)`
href: #;
variant: body2;
color: red;
`;
function App() {
return (
<StyledLink className="classic">
<div>Forgot?</div>
</StyledLink>
);
}

You should make your Link component just like below:
// Link.js
import { Link } from '#material-ui/core/Link';
import styled from 'styled-components';
export default styled(Link)`
display: block;
color: #F51963;
text-decoration: none;
`;

You can use the <Link> on top of other divs or buttons for example
<Link><button className="Btn">Forgot?</button></Link>
you can then do two things to style the button / divs
<Link><button className="Btn" style={{backgroundColor: 'red'}}>Forgot?</button></Link>
or the second is import a separate css file
import classes from './ComponentName.module.css'
and then give a style
<Link><button className={classes.Btn}>Forgot?</button></Link>

Related

React Typescript: property 'body' does not exist type 'DefaultTheme'

I am new to React and Typescript, I am trying to add dark-mode to my project,
I created globalStyle component, Themes component and using Themeprovider.
I am facing an issue on my globalStyle component when it says:
property 'body' does not exist type 'DefaultTheme'
My globalStyles.tsx code is as follow:
import { createGlobalStyle} from "styled-components"
export const GlobalStyles = createGlobalStyle`
body {
background: ${({ theme }) => theme.body};
color: ${({ theme }) => theme.text};
font-family: Tahoma, Helvetica, Arial, Roboto, sans-serif;
transition: all 0.50s linear;
}`
my Themes.tsx:
export const lightTheme = {
body: '#FFF',
text: '#363537',
background: '#363537',
}
export const darkTheme = {
body: '#363537',
text: '#FAFAFA',
background: '#999',
}
and my Themeprovider code on App.tsx:
<ThemeProvider theme={this.state.theme === 'light' ? lightTheme : darkTheme}>
<>
<GlobalStyles/>
<ul className='tickets'>
{filteredTickets.map((ticket) => (
<li key={ticket.id} className={ticket.toggle ? 'expand' : 'ticket'}>
<h5 className='title'>{ticket.title}</h5>
<button onClick={() => this.onHide(ticket.id)}>Hide</button>
<p className={ticket.toggle ? 'show-more' : 'content'}>{ticket.content}</p>
<button onClick={()=> this.onToggle(ticket.id)}>{ticket.toggle ? 'Show less' : 'Show more'}</button>
<footer>
<div className='meta-data'>By {ticket.userEmail} | { new Date(ticket.creationTime).toLocaleString()}</div>
</footer>
</li>))}
</ul>
</>
</ThemeProvider>
What am I doing wrong and why theme.body and theme.text is not recognized on globalStyles.tsx?
Thanks !
I'm basing this answer on the following link: https://spectrum.chat/styled-components/general/i-cant-use-my-theme-in-createglobalstyle-function-styled-components-v4-react-v16-6-3~0978b404-ab71-45c9-8f75-0862abde4eb5
createGlobalStyle can accept a shape for the theme:
createGlobalStyle<{theme: ThemeType}>
From the styled-components docs, there's this (https://styled-components.com/docs/api#typescript):
declare module 'styled-components' {
export interface DefaultTheme {
borderRadius: string;
colors: {
main: string;
secondary: string;
};
}
}
So, I suggest you set up an interface for your theme, as above, and then pass it into createGlobalStyle in place of ThemeType
So the answer above fails, as useTheme does not know what type you passed to createGlobalStyles.
But this is a typescript workaround that doesn't require you to use ts-ginore:
As jnpdx suggested, you do need to type the createGlobalTheme object:
createGlobalStyle<{theme: ThemeType}>
The only working solution I have figured out so far is to post-type your useTheme variable like so:
const theme = useTheme() as ThemeType;
Based on the styled-components docs (https://styled-components.com/docs/api#typescript) I created an interface for the body type:
export interface DefaultTheme {
body: string;
}
export const GlobalStyle = createGlobalStyle<{ theme: DefaultTheme }>`
body{
background-color: ${({ theme }) => theme.body};
color: var(--font-color);
}
`;
This works pretty well for me.

use tailwind classes into styled-components

Can I use tailwind classes ( like colors ) into the styled-components ?
I want to use some classes instead of CSS styles to style my components
this is the way add class in styled-components:
const Button = styled.button.attrs(props => ({
className: "small",
}))`
/* other styles */
`;
so unlike styles, attrs className is only one single string, and I want to add classes for size, color, display and etc.
I have to concat them all every time, is there a better way ?
You can use macro, I suggest trying twin.macro:
import tw, { styled } from 'twin.macro'
const Input = styled.input`
color: purple;
${tw`border rounded`}
${({ hasHover }) => hasHover && tw`hover:border-black`}
`
const Component = () => <Input hasHover />

Using Typescript with Styled Components and Material UI

Using Typescript with MUI+Styled-Components and you have to directly pass props to MUI elements due to type errors….
const Index = () => {
return (
<StyledButton
variant="contained"
>
Hello World
</StyledButton>
)}
const StyledButton = styled(Button)`
background: red;
color: white;
`;
However, this will error the following:
Type '{ children: string; variant: "contained"; }' is not assignable to type '(IntrinsicAttributes & Pick>) | PropsWithChildren, "form" | "style" | "title" | ... 284 more ... | "variant"> & Partial<...>, "form" | ... 286 more ... | "variant"> & { ...; } & { ...; }) | (IntrinsicAttributes & ... 3 more ... & { ...; })’
When you directly pass in props such as below, then this error goes away. Even using 0 props and 0 children on the Styled MUI element, it gives the error.
const StyledButton = styled(props => <Button {...props} />)`
background: red;
color: white;
`;
This should work fine with MUI >= 4.*
For earlier versions, from this tutorial, try enforcing the type of StyledButton:
const StyledButton = styled(Button)`
background: red;
color: white;
` as typeof(Button);
I accidentally solved this by installing #types/styled-components / styled-components, which I required anyways to get styled/theme/TS all playing nicely together:
import React from "react";
import styled from "styled-components";
import { Theme, useTheme } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
const StyledCustomButton: React.FC<{
theme: Theme;
}> = styled(({ ...props }) => <Button {...props}>Test</Button>)`
&& {
padding-bottom: ${(props) => props.theme.spacing(2)}px;
}
`;
const CustomButton: React.FC = () => {
const theme: Theme = useTheme();
return <StyledCustomButton theme={theme} />;
};
export default CustomButton;

creating css rule with "Styled-Components"

I am using the awesome "Styled-Components"
but I am now using another package that wraps an element inside it so I can't push my StyledComponents there as I don't want to change his package.
I saw glamor has a nice trick.
Is that supported with StyledComponents?
import { css } from 'glamor';
let rule = css({
color: 'red',
})
<div {...rule}>
zomg
</div>
If you think about why I need it, here is an example:
this is an external package I'm using:
External = props => (
<div>
<input style={props.inputStyle} className={props.inputClass} />
</div>
);
so you can see I need to pass in a json style or className
so Glamor will work here, but I dont want to use it just for this scenario.
I'm already enjoying StyledComponent
Thanks
If I understood your query, you can define css rules to a component, like this
import styled from 'styled-components'
const Wrapper = styled.div`
color: 'red';
font-weight: bold;
background-color: ${ props => props.color === 'primary' ? 'green' : 'red' }
`
export const Component = () => {
<Wrapper color='primary'>
I have a red text, and bold font-weight.
</Wrapper>
}

Put a Font Awesome icon dynamically on input text background using React and react-fa

I'm using ReactJs and react-fa to access Font Awesome icons. I need to put one of the icons inside a text input dynamically.
Here is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Icon } from 'react-fa';
import '../index.css';
class SearchInput extends Component {
static propTypes = {
onKeyUp: PropTypes.object,
placeholder: PropTypes.placeholder,
iconName: PropTypes.string
};
handleKeyUp = (content) => {
console.log(content);
}
render() {
let icon = <Icon name={this.props.iconName} />;
let extra = {
backgroundImage: icon
}
return (
<input className='ux-search-input' style={extra} type='text' onKeyUp={this.handleKeyUp} placeholder={this.props.placeholder} />
);
}
};
export default SearchInput;
This does not work - no icons at all. Repair that in that case I have no URLs to match, as the icon variable will be a ReactJs component.
react-fa is a React component, and it renders as html like <i class="fa fa-name" />, so you can't use it as a style. You should use something like this:
return (
<span>
{ icon }
<input className='ux-search-input' style={extra} type='text' onKeyUp={this.handleKeyUp} placeholder={this.props.placeholder} />
</span>
);
and add some styling to match proper icon position.
Instead of using React component, try using a regular icon tag in front of the input field, and then use css to move the icon to the appropriate position.
For example:
JSX:
<i class={this.props.iconName} id="icon" />
CSS:
#icon {
// Adjust margins and position to fit the input background
margin-left: 30px;
}

Categories