Given the css
.App {
font-family: sans-serif;
text-align: center;
}
.App:hover {
background-color: red;
}
and jsx code
import "./styles.css";
import { useRef } from "react";
export default function App() {
const r = useRef();
const handleClick = () => {
console.log(r.current.style.backgroundColor);
};
return (
<div className="App" ref={r} onClick={handleClick}>
something
</div>
);
}
See codesandbox
I want to get the active background color of div (which is red). But the code give me nothing. What's the right way of doing that?
.style only tells you the inline style on the element, and this div has no inline style. If you want to know the style that results when combining inline style and css selectors, you need getComputedStyle
const handleClick = () => {
console.log(window.getComputedStyle(r.current).backgroundColor);
}
el.style.X is not working correctly. Insteadof this use window.getComputedStyle(el) and u can get full list of styles. As a example u can see it.
Related
I want to change the texts by icons, what do I have to do to change the texts by icons ?
I have to find the result like this :
file.ts:
ngAfterViewInit() {
this.current.paginator = this.paginator;
const lastBtn = this.el.nativeElement.querySelector(
'.mat-paginator-navigation-last'
);
if (lastBtn) {
lastBtn.innerHTML = 'Last';
}
const firstBtn = this.el.nativeElement.querySelector(
'.mat-paginator-navigation-first'
);
if (firstBtn) {
firstBtn.innerHTML = 'First';
}
}
If you want to change the button icons, it is possible to do so.\
In order to do so, we need to alter the html that is being generated by the mat-paginator.
The following directive does it:
#Directive({
selector: '[customPaginatorIcons]'
})
export class CustomPaginatorIcons implements AfterViewInit {
constructor(
private el: ElementRef,
private renderer2: Renderer2
) {}
ngAfterViewInit(): void {
this.setFirstIcon();
this.setPreviousIcon();
this.setNextIcon();
this.setLastIcon();
}
private replaceSvgWithIcon(
btn: HTMLButtonElement,
iconName: string
): HTMLSpanElement {
this.renderer2.removeChild(btn, btn.querySelector('svg'));
const icon: HTMLSpanElement = this.renderer2.createElement('span');
this.renderer2.addClass(icon, 'material-icons');
icon.innerHTML = iconName;
this.renderer2.appendChild(btn, icon);
return icon;
}
private setFirstIcon(): void {
const btn = this.el.nativeElement.querySelector(
'.mat-mdc-paginator-navigation-first'
);
if (btn) {
this.replaceSvgWithIcon(btn, 'skip_previous');
}
}
private setPreviousIcon(): void {
const btn = this.el.nativeElement.querySelector(
'.mat-mdc-paginator-navigation-previous'
);
if (btn) {
const icon = this.replaceSvgWithIcon(btn, 'play_arrow');
this.renderer2.setStyle(icon, 'transform', 'rotate(180deg)');
}
}
private setNextIcon(): void {
const btn = this.el.nativeElement.querySelector(
'.mat-mdc-paginator-navigation-next'
);
if (btn) {
this.replaceSvgWithIcon(btn, 'play_arrow');
}
}
private setLastIcon(): void {
const btn = this.el.nativeElement.querySelector(
'.mat-mdc-paginator-navigation-last'
);
if (btn) {
this.replaceSvgWithIcon(btn, 'skip_next');
}
}
}
Now onto the why.
Directive: we create our attribute directive that will adjust the icons of the MatPaginator. Attribute Directives are recommended when we only want to edit the html of something.
AfterViewInit: we can only edit the contents of the MatPaginator html after it has been fully initialise. The AfterViewInit lifecycle hook is the best hook for the task.
ElementRef: this provides access to the HTML code that our directive is placed on.
Renderer2: the recommended utility to modify HTML elements safely. It is the basis that directives like ngStyle and ngClass use being the scenes. We can achieve the same goal by directly editing the DOM elements, however, this may raise errors if we edit it incorrectly.
setFirstIcon, setPreviousIcon, setNextIcon, setLasttIcon: these are very similar methods, they search for the button that needs to be updated and if it exists, they call the replaceSvgWithIcon method to perform the actual changes. Only exception to this is the setPreviousIcon method since there is no icon that matches what you want. To achieve the look you want, I rotate the next icon.
replaceSvgWithIcon: starts by removing the <svg>...</svg> tag from the button. This is the tag that contains the actual image for the icon, the remaining HTML in the button element is for other things like the ripple. Once the element has been removed, we create a new HTMLSpanElement. It is on this element that we will set the material-icons class (so that it uses the Material Icons), and the value of the icon. After this is done, we append it to the provided button and return it (we return the element in case we want to modify something else that is not generic).
To use this directive, we simply call on the html selector of the paginator:
<mat-paginator
...
customPaginatorIcons>
</mat-paginator>
The above case is meant for Angular 15.
For previous versions, simple remove the '-mdc' from the selectors, like so:
'.mat-mdc-paginator-navigation-first' to `'.mat-paginator-navigation-first';
'.mat-mdc-paginator-navigation-previous' to '.mat-paginator-navigation-previous';
'.mat-mdc-paginator-navigation-next' to '.mat-paginator-navigation-next';
'.mat-mdc-paginator-navigation-last' to '.mat-paginator-navigation-last';
You can also get it only with .css
In styles.css
.mat-mdc-paginator-navigation-first svg path{
d:path("M6.5 18q-.425 0-.713-.288Q5.5 17.425 5.5 17V7q0-.425.287-.713Q6.075 6 6.5 6t.713.287Q7.5 6.575 7.5 7v10q0 .425-.287.712Q6.925 18 6.5 18Zm10.45-1.025l-6.2-4.15q-.45-.3-.45-.825q0-.525.45-.825l6.2-4.15q.5-.325 1.025-.038q.525.288.525.888v8.25q0 .6-.525.9q-.525.3-1.025-.05Z")
}
.mat-mdc-paginator-navigation-previous svg path{
d:path("M7.05 16.975q-.5.35-1.025.05q-.525-.3-.525-.9v-8.25q0-.6.525-.888q.525-.287 1.025.038l6.2 4.15q.45.3.45.825q0 .525-.45.825Z")
}
.mat-mdc-paginator-navigation-next svg path{
d:path("M7.05 16.975q-.5.35-1.025.05q-.525-.3-.525-.9v-8.25q0-.6.525-.888q.525-.287 1.025.038l6.2 4.15q.45.3.45.825q0 .525-.45.825Z")
}
.mat-mdc-paginator-navigation-last svg path{
d:path("M17.5 18q-.425 0-.712-.288q-.288-.287-.288-.712V7q0-.425.288-.713Q17.075 6 17.5 6t.712.287q.288.288.288.713v10q0 .425-.288.712q-.287.288-.712.288ZM7.05 16.975q-.5.35-1.025.05q-.525-.3-.525-.9v-8.25q0-.6.525-.888q.525-.287 1.025.038l6.2 4.15q.45.3.45.825q0 .525-.45.825Z")
}
.mat-mdc-paginator-navigation-previous svg
{
transform:rotate(180deg) translateX(3px)
}
.mat-mdc-paginator-navigation-next svg
{
transform:translateX(3px)
}
I'm trying to learn ReactJS and now I'm making a small project that consists of a button that every time I click it, it will show an html element (as I still couldn't get the button to work, I haven't created the element yet, so the element it should create is an h1), but when I click the button nothing happens, could anyone help me? (sorry for any spelling mistakes, I'm still learning English)
This is my code:
import Container from "./App.style";
import Button from "./Components/Button/Button.jsx";
const App = () => {
const createElement = () => {
return(
<h1>Hey</h1>
)
}
return (
<>
<Container>
<h1>Criador De Elementos</h1>
<Button onClick={ createElement }>Criar Elemento</Button>
</Container>
</>
);
}
export default App;
import React from "react";
import StylesButton from "./Button.style";
const Button = ( {onClick, children} ) => {
return (
<StylesButton onClick={ onClick }> { children } </StylesButton>
);
}
export default Button;
Looks like you your code is correct. But my question is where you want to that h1 element. If you want h1 to Your DOM than you must create an h1 to your DOM and control value of h1 by using state (by Using useState Hook).
if you want to render your h1 element then you can do like this.
import {useState} from 'react';
import Container from "./App.style";
import Button from "./Components/Button/Button.jsx";
const App = () => {
const [heading,setHeading] = useState("");
const createElement = () => {
setHeading("Hey");
}
return (
<>
<Container>
<h1>Criador De Elementos</h1>
<Button onClick={ createElement }>Criar Elemento</Button>
<h1>{heading}</h1>
</Container>
</>
);
}
export default App;
import React from "react";
import StylesButton from "./Button.style";
const Button = ( {onClick, children} ) => {
return (
<StylesButton onClick={ onClick }> { children } </StylesButton>
);
}
export default Button;
I have a export const with a big text, and in the middle I want to add a hyperlink element, but this is not working.
My code:
const myEmail = 'example#example.com'
export const EXAMPLE = `Example of email: ${myEmail}`
Where I import:
import React, { FC } from 'react'
import { EXAMPLE } from '../../constants/ui.constants'
const Example: FC<{}> = () => {
return <div>{EXAMPLE}</div>
}
export default Example
But this shows like this:
How can I show the email like this ?
(this was edit through inspect tools)
You can use dangerouslySetInnerHTML, but you have to be very sure that whatever you are injecting is not something the user has control over, otherwise you will be introducing a XSS vulnerability.
import React, { FC } from 'react'
import { EXAMPLE } from '../../constants/ui.constants'
const Example: FC<{}> = () => {
return <div dangerouslySetInnerHTML={EXAMPLE} />
}
export default Example
I just meet a problem that could not load the CSS inside react function component with material UI. Though I fixed it, I am still curious about the reason.
In the beginning, I write something like this, where I put both makeStyles and useStyles inside the function component. Then, I find that the class name is correctly assigned to the element, but no css is loaded.
import makeStyles from "material-UI"
import styles from "styles.js"
export default function alertPage() {
const useStyles = makeStyles(styles);
const classes = useStyles();
const [alert, setalert] = React.useState();
const showAlert = () => {
setalert(<p className={classes.text}></p>)
}
return (
<button onClick={showAlert}></button>
{alert}
)
}
Then, I put makeStyles outside the function, everything works correctly.
import makeStyles from "material-UI"
import styles from "styles.js"
const useStyles = makeStyles(styles);
export default function alertPage() {
const classes = useStyles();
const [alert, setalert] = React.useState();
const showAlert = () => {
setalert(<p className={classes.text}></p>)
}
return (
<button onClick={showAlert}></button>
{alert}
)
}
Then, I tried this code putting both inside function component again, but return the HTML directly, which still works.
import makeStyles from "material-UI"
import styles from "styles.js"
export default function alertPage() {
const useStyles = makeStyles(styles);
const classes = useStyles();
return (
<p className={classes.text}></p>
)
}
Then, I check the react official site and find that they always put CSS outside the function component, but not getting any sentences mentioned that this is required or why.
My guess is that I misunderstand the scope of the const or how CSS is actually loaded in the browser. If anybody could tell me the reason, or which piece of knowledge I missed, like js, ts, react, or how the browser works?
Thanks!
From the Material UI docs, you should have something like the below:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
root: {
// Your styles
},
});
export default function Hook() {
const classes = useStyles();
// Rest of your code
}
If you have styles in a correctly formatted import, you should be able to add them directly in the makeStyles declaration:
const useStyles = makeStyles(styles)
React Router adds an active class to NavLinks when you are on the page that they link to. How can I access this property with Styled Components. I need to styled menu items differently when you are on their page.
const LinkElem = styled(NavLink)`
font-size: 16px;
font-weight: 400;
${props => console.log(props)};
&:hover {
color: ${props => props.theme.colorOrange};
}
`;
const Menu = props => {
const { me } = props;
return (
<MenuElem>
<li>
{me ? (
<LinkElem to="/account">Account</LinkElem>
) : (
<LinkElem to="/login">Log in / sign up</LinkElem>
)}
</li>
</MenuElem>
);
};
The prop className is getting added to the children of NavLink and so its not accessible at NavLink level. The docs were not clear about this. Therefore, we cannot check for props.className === 'active' and add styles.
Instead, you could just resort to css inside styled components for your use:
const LinkElem = styled(NavLink)`
// example style
&.active {
color: ${props => props.theme.orange }
}
`;
As of react-router v4, you can style the active state of NavLink without any dependencies using activeClassName and Styled Components' attrs() function:
export const StyledNavLink = styled(NavLink).attrs({
activeClassName,
})`
&.${activeClassName} {
background: red;
}
`;
Related documentation:
activeClassName
attrs()
const StyledLink = styled(NavLink)`
color: blue;
&.active {
color: red;
}
`;
If you are using object syntax in styled-components, you can implement the next solution:
const activeClassName = 'nav-item-active'
export const StyledLink = styled(NavLink).attrs({
activeClassName,
})(props => ({
height: '20px',
width: '20px',
backgroundColor: 'green',
['&.' + props.activeClassName]: {
backgroundColor: 'red'
}
}))
Declare variable with the name of the active class of react router
Style the NavLink and pass as attribute activeClassName
From the props get the activeClassName
Declare the conditional styles in case of the activeClassName being present
You can check a live example in the next StackBlitz project:
https://stackblitz.com/edit/react-hcudxz
Styled component:
import { NavLink } from 'react-router-dom';
export const MyNavLink = styled(NavLink)`
&.${props => props.activeClassName} {
color: red;
}
`;
Usage:
<MyNavLink to="/dashboard" activeClassName="anyClassNameWillWork">Dashboard</MyNavLink>
Tested with:
react-router-dom 5.1.2
styled-components 5.0.1
The string you added to NavLink's activeClassName will join to className later when you hit the specific route. Since styled components support pure css,
&.{yourActiveClassName} { #css goes here}
should work.
I'm not particularly keen on the &.active approach if you're trying to build a styled-component that is router independent, so I created asNavLink to deal with this:
npm install as-nav-link --save
Given a component:
const MyNavAnchor = styled(({
as: T = 'a',
active, // destructured so it is not passed to anchor in props
...props
}) => <T {...props} />)({
textDecoration: 'blink',
color: 'blue',
}, ({ active }) => (active && {
color: 'red',
}));
You can use it like this:
import asNavLink from 'as-nav-link';
const MyNavLink = asNavLink(config)(MyNavAnchor);
And it will pass down the active prop to your styled component.
config is optional and can include an isActive function (as per ReactRouter's NavLink) and an activeProp string (the prop name that is passed to your component).
I think it's simplest decision.
const StyledLink = styled(NavLink)`
color: blue;
&.${props => props.activeClassName} {
color: red;
}
`;
react-router now has activeStyle props, which can be used to style active link easily:
<NavLink
to="/faq"
activeStyle={{
fontWeight: "bold",
color: "red"
}}
>
FAQs
</NavLink>
With styled-components:
const LinkElem = styled(NavLink)`
font-size: 16px;
font-weight: 400;
`;
<LinkElem
activeStyle={{
fontWeight: 'bold',
color: 'red',
}}
></LinkElem>;