I am trying to create a component for accessibility and have the option to change settings such as dark mode, higher contrast, font size, etc.
I've made a component as a bootstrap modal where settings for accessibility can be changed. Dark mode and higher contrast are implemented and working.
The problem I am running into is changing font sizes. I want to be able to dynamically set the font size to a smaller or larger size. My idea was to add a class to the <body> tag since there are some articles out there showing how to set classes in the body tag dynamically in _document.js.
I cannot figure out a good way to implement this and might be looking at it the complete wrong way.
For a better view of what's done so far I have setup a CodeSandbox with the complete code:
https://codesandbox.io/s/nextjs-react-bootstrap-accessibility-exndhh
As of now the accessibility component looks like this:
import { useState, useEffect } from "react";
import { useTheme } from "next-themes";
import { Button, Modal, Form } from "react-bootstrap";
import { UniversalAccess } from "./Icons";
const Accessibility = () => {
// A11Y - Accessibility modal
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
// A11Y - Accessibility themes
const [mounted, setMounted] = useState(false);
const { theme, setTheme, resolvedTheme } = useTheme();
// When mounted on client, now we can show the UI
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return (
<>
<Button
variant="warning"
className="px-4 py-2 ms-lg-3 d-flex align-items-center"
onClick={handleShow}
>
<UniversalAccess className="me-2" />
Accessibility
</Button>
<Modal show={show} onHide={handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>Accessibility settings</Modal.Title>
</Modal.Header>
<Modal.Body>
<p className="h5">Colors</p>
<Form.Check
type="switch"
id="dark-mode"
label="Dark mode"
onChange={() => setTheme(theme === "dark" ? "light" : "dark")}
checked={resolvedTheme === "dark"}
/>
<Form.Check
type="switch"
id="contrast-mode"
label="Higher contrast"
onChange={() =>
setTheme(theme === "contrast" ? "light" : "contrast")
}
checked={resolvedTheme === "contrast"}
/>
<div className="my-4">
<p className="h5">Font size/type</p>
<div className="d-flex mb-1 align-items-end">
<div className="d-flex flex-column align-items-center">
<Button
className="rounded-pill d-flex align-items-center justify-content-center"
variant="outline-primary"
style={{ width: "30px", height: "30px" }}
>
<span style={{ fontSize: "0.7rem" }}>A</span>
</Button>
<p>Small</p>
</div>
<div className="d-flex flex-column align-items-center">
<Button
className="mx-3 rounded-pill d-flex align-items-center justify-content-center"
variant="outline-primary"
style={{ width: "40px", height: "40px" }}
// Should be active because default font size
active
>
<span style={{ fontSize: "1rem" }}>A</span>
</Button>
<p>Default</p>
</div>
<div className="d-flex flex-column align-items-center">
<Button
className="rounded-pill d-flex align-items-center justify-content-center"
variant="outline-primary"
style={{ width: "50px", height: "50px" }}
>
<span style={{ fontSize: "1.5rem" }}>A</span>
</Button>
<p>Large</p>
</div>
</div>
<Form.Check
type="switch"
id="dyslexia-mode"
label="Dyslexia font"
/>
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
);
};
export default Accessibility;
Eventually I'd like to have the option to changes fonts dynamically as well any suggestions here are more tan welcome!
The goal here is not to become fully WCAG compliant but at least have some of it.
Perhaps there's one of those handy dandy react libraries out there and have not found it yet.
Typically, we (my company) leave that up to the user agent to determine the font and font size. For example, in Firefox, under "Fonts" you can tell the browser to override a webpage's font and font size; also, under "Zoom" you change the page zoom. In Chrome, under "Appearance," you can do the same.
This appears to be the recommended approach by WCAG2.1 and by me (and you'll see why below).
The scaling of content is primarily a user agent responsibility. User agents that satisfy UAAG 1.0 Checkpoint 4.1 allow users to configure text scale. The author's responsibility is to create Web content that does not prevent the user agent from scaling the content effectively.
When designing for accessibility, the best advice I can give would be to determine what WCAG2.1 considers sufficient for resizing text.
That said, the problems you're going to run into because of nextjs and react-bootstrap:
Persistence -- using context inside a modal gets super hacky (you'd need to have the context always in the DOM, which means the modal would need to reside under div#__next, which isn't??? currently possible with react-bootstrap because it appends modals to the body and outside of div#__next container) and
local storage is client-side only, so you'll get a massive CLS
when the page is SSR'd.
Support -- according to WCAG, you need to support up to a 200% font size. Therefore, you'll probably want to have some sort of stepping: 100%, 125%, 150%, 175%, 200%.
Layout -- by supporting variable font sizing, you'll also need to support variable layouts. Otherwise, the text can take up more space than visually expected: breaking containers, breaking form inputs, elongating buttons vertically, and wrapping some sort of text that makes it harder to read. This is expected when changing the font in a user-agent, but since you're supporting font resizing, you'll definitely want to also support different layouts (as mentioned in the sufficient link above).
Screen readers -- currently your font size buttons aren't communicating their intent; they're being read as "Push button" without any context. You'll need to use semantic markup or aria attributes for it to be picked up a screen reader. If you want to dive into it, I know for sure that Mac OS and most popular Linux distros have built in screen readers in their accessibility system settings -- no idea about Windows.
Is it possible to accomplish the above? Yes, but maybe not (as easy/at all) with the 3rd party libraries you're using.
Before solving the above, I'd ask myself: At what cost (to you, a company or a client) is this going to take to solve these problems, and more importantly, what value does this feature bring that can't be accomplished natively?
Everything is in the title. Here is the CodeSandbox with reproduction !
When using MUI's ButtonGroup, the layout is fine with three "regular" buttons:
<ButtonGroup variant="contained" aria-label="outlined primary button group">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
Result:
But as soon as we add an href to one of the buttons, it breaks the layout, like so:
<ButtonGroup variant="contained" aria-label="outlined primary button group">
<Button href="test.com">One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
Result:
Is there any way to fix this ? I don't want to have to use the trick of onClick and location.replace or location.href...
Also, maybe I should post this as an issue on MUI's GitHub? I'm guessing only if it is relevant and not fixable, but there are so many I doubt they would see it.
Use the prop LinkComponent="button":
import * as React from "react";
import Button from "#mui/material/Button";
import ButtonGroup from "#mui/material/ButtonGroup";
export default function BasicButtonGroup() {
return (
<ButtonGroup variant="contained" aria-label="outlined primary button group">
<Button LinkComponent="button" href="test.com">
One
</Button>
<Button>Two</Button>
<Button>Three</Button>
</ButtonGroup>
);
}
Demo: https://codesandbox.io/s/basicbuttongroup-material-demo-forked-43pmhn?file=/demo.js:0-430
I am a new material UI, I am trying to use Typography, if I don't use variant in the typography tag, it is fine
<div className="login-details">
<Typography>{details ? details.email : "N/A"} |</Typography>
<Button type="link" onClick={()=> document.dispatchEvent(new CustomEvent("user.start_logout"))}>
logout
</Button>
</div>
if I use a variant like below, the UI is falling apart
<div className="login-details">
<Typography variant="h2">{details ? details.email : "N/A"} |</Typography>
<Button type="link" onClick={() => document.dispatchEvent(new CustomEvent("user.start_logout"))}>
logout
</Button>
</div>
Please help me.
Thanks in Advance.
Not using a variant is equivalent to variant="body1". Check your h2 style, particularly the line height and margins. Refer to the documentation on how to customise the default typography.
I have a button to calculate statistics, what I want is that button change after clicking on it to calculating with animated load spinner, this is what I tried
<button className="bg-green-A200 rounded text-black mt-20 py-2 px-8 h-28" onClick={consulterStat} disabled={loading}>
{loading && (
<i
className="fa fa-refresh fa-spin animate-spin "
style={{ marginRight: "20px" }}
/>
)}
{loading && <span>calculate</span>}
{!loading && <span>calculating</span>}
</button>
When I click on button this what i do
setLoading(true)
setTimeout(() => {
setLoading(false)
}, 2000);
And this part works because every time I click the text change from calculate to calculating for 2 seconds, but what I want is to get the same button with the same style and everything just with different text and an animated circle spinner showing inside the button beside the text calculating.
I'm using primereact and according to there website this is how they change there icon size.
However this doesn't work in jsx as it won't let you directly reference style without it being an object.
Are there any workarounds to this?
EDIT: Code for Button where icon is nested in below:
<Button
label=""
icon="pi pi-cog"
className="cogIcon"
onClick={(e) => this.setState({visibleRight:true})}
style={{marginTop:'.25em', marginRight:'.25em'} }
/>
In the link you provide, they have an example
<i class="pi pi-check" style="font-size: 3em"></i>
Just add fontSize: 3em (or the size you want).
<Button
label=""
icon="pi pi-cog"
className="cogIcon"
onClick={(e) => this.setState({visibleRight:true})}
style={{marginTop:'.25em', marginRight:'.25em', fontSize: '3em'} }
/>