Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PR]: Improve Accessibility of Components - Semantic HTML etc #16

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import BookSearch from "./components/BookSearch";
import BookList from "./components/BookList";
import Header from "./components/Header";
import useFetchBooks from "./hooks/useFetchBooks";
import CenterdSpinner from "./components/CenteredSpinner";
import CenteredSpinner from "./components/CenteredSpinner";
import "./App.css";

const App = () => {
Expand All @@ -13,18 +13,19 @@ const App = () => {
language: "en",
sortType: "relevance",
});

const { books, loading, error, success } = useFetchBooks(searchParams);

const handleSearch = (searchValue, searchType, language, sortType) => {
setSearchParams({ searchValue, searchType, language, sortType });
};

return (
<div>
<div role="main"> {/* Indicate main content for assistive technologies */}
<Header />
<BookSearch onSearch={handleSearch} searchParams={searchParams} />
{loading && <CenterdSpinner />}
{error && <p>Error: {error.message}</p>}
{loading && <CenteredSpinner />}
{error && <p aria-live="assertive">Error: {error.message}</p>} {/* Announce error messages */}
{success && <BookList books={books} />}
</div>
);
Expand Down
19 changes: 16 additions & 3 deletions src/components/BookItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ export default function BookItem({ book }) {

return (
<div>
<Card sx={cardStyle} onClick={handleOpen}>
<Card
sx={cardStyle}
onClick={handleOpen}
role="button" // Ensure the Card behaves like a button
tabIndex={0} // Make the Card focusable
onKeyPress={(e) => { if (e.key === 'Enter') handleOpen(); }} // Allow keyboard activation
aria-label={`View details for ${title} by ${authors?.join(", ")}`} // Provide an accessible label
>
<CardMedia
component="img"
sx={{ objectFit: "contain" }}
height="200"
image={imageLinks?.thumbnail?.replace(/&edge=curl/g, "")}
alt={`Cover of ${title} by ${authors?.join(", ")}`}
alt={`Cover of ${title} by ${authors?.join(", ")}`} // Alt text already descriptive
/>
<CardActions
disableSpacing
Expand All @@ -40,7 +47,13 @@ export default function BookItem({ book }) {
justifyContent: "center",
}}
>
<MoreHorizIcon sx={{ height: "2em", width: "2em" }} />
<MoreHorizIcon
sx={{ height: "2em", width: "2em" }}
aria-label="More options" // Add label for icon button
role="button" // Indicate that it's a button
tabIndex={0} // Make it focusable
onKeyPress={(e) => { if (e.key === 'Enter') handleOpen(); }} // Allow keyboard activation
/>
</CardActions>
</Card>
<BookItemBack
Expand Down
13 changes: 5 additions & 8 deletions src/components/BookItemBack.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function BookItemBack({
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-authors"
closeAfterTransition // Improves focus management and accessibility
>
<Box
sx={{
Expand All @@ -42,6 +43,8 @@ export default function BookItemBack({
alignItems: "center",
justifyContent: "space-evenly",
}}
role="dialog" // Indicate this Box is a dialog
aria-modal="true" // Indicate it is a modal
>
<Box className="text-wrapper">
<Typography id="modal-modal-title" variant="h6" component="h2">
Expand All @@ -51,14 +54,8 @@ export default function BookItemBack({
{authors?.join(", ")}
</Typography>
</Box>
<IconButton aria-label="link to book">
<a
href={canonicalVolumeLink}
target="_blank"
rel="noopener noreferrer"
>
<LinkIcon sx={{ height: "2em", width: "2em" }} />
</a>
<IconButton aria-label="Link to book" onClick={() => window.open(canonicalVolumeLink, '_blank', 'noopener,noreferrer')}>
<LinkIcon sx={{ height: "2em", width: "2em" }} />
</IconButton>
</Box>
</Modal>
Expand Down
6 changes: 6 additions & 0 deletions src/components/BookList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const BookList = ({ books }) => {
const indexOfFirstBook = indexOfLastBook - booksPerPage;
const currentBooks = books.slice(indexOfFirstBook, indexOfLastBook);
const paginate = (pageNumber) => setCurrentPage(pageNumber);

return (
<>
<Box
Expand All @@ -21,14 +22,19 @@ const BookList = ({ books }) => {
gap: "1rem",
marginBottom: "2rem",
}}
role="region" // Indicate this is a region of related content
aria-labelledby="book-list-title" // Link to the heading
>
<h2 id="book-list-title" style={{ display: 'none' }}>Book List</h2> {/* Hidden heading for screen readers */}
{currentBooks.map((book, index) => (
<BookItem key={book.id || index} book={book} />
))}
</Box>
<Box
className="pagination-wrapper"
sx={{ display: "flex", justifyContent: "center" }}
role="navigation" // Indicate this is a navigation region
aria-label="Pagination controls" // Provide a label for navigation
>
<Paginate
booksPerPage={booksPerPage}
Expand Down
9 changes: 8 additions & 1 deletion src/components/BookSearch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ const BookSearch = ({ onSearch, searchParams }) => {
alignItems: "center",
marginBottom: 2,
}}
role="region" // Indicate this is a search region
aria-labelledby="book-search-title" // Link to the title
>
<h2 id="book-search-title" style={{ display: 'none' }}>Book Search</h2> {/* Hidden heading for screen readers */}
<TextField
label="Search for books"
value={searchValue}
Expand All @@ -51,17 +54,19 @@ const BookSearch = ({ onSearch, searchParams }) => {
InputProps={{
endAdornment: (
<InputAdornment position="end">
<Search />
<Search aria-hidden="true" /> {/* Hide icon from screen readers */}
</InputAdornment>
),
}}
aria-label="Search for books" // Provide label for assistive technologies
/>
<Box sx={{ display: "flex", gap: 2, width: "100%" }}>
<Select
value={searchType}
onChange={(e) => setSearchType(e.target.value)}
variant="outlined"
fullWidth
aria-label="Select search type" // Provide label for assistive technologies
>
<MenuItem value="title">Title</MenuItem>
<MenuItem value="author">Author</MenuItem>
Expand All @@ -72,6 +77,7 @@ const BookSearch = ({ onSearch, searchParams }) => {
onChange={(e) => setLanguage(e.target.value)}
variant="outlined"
fullWidth
aria-label="Select language" // Provide label for assistive technologies
>
{languages.map((language) => (
<MenuItem key={language.lang} value={language.lang}>
Expand All @@ -84,6 +90,7 @@ const BookSearch = ({ onSearch, searchParams }) => {
onChange={(e) => setSortType(e.target.value)}
variant="outlined"
fullWidth
aria-label="Select sort type" // Provide label for assistive technologies
>
<MenuItem value="relevance">Relevance</MenuItem>
<MenuItem value="newest">Newest</MenuItem>
Expand Down
17 changes: 9 additions & 8 deletions src/components/CenteredSpinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import React from 'react';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';

interface CenterdSpinnerProps{
height?: number;
size?: number;
interface CenteredSpinnerProps {
height?: number;
size?: number;
}

const CenterdSpinner = ({height, size}:CenterdSpinnerProps) => {

const CenteredSpinner = ({ height, size }: CenteredSpinnerProps) => {
return (
<Box
sx={{
Expand All @@ -18,12 +17,14 @@ const CenterdSpinner = ({height, size}:CenterdSpinnerProps) => {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
mt: 2
mt: 2,
}}
role="status" // Indicate that this is a loading status
aria-live="polite" // Notify screen readers of loading status
>
<CircularProgress size={size}/>
<CircularProgress size={size} aria-label="Loading..." /> {/* Provide label for accessibility */}
</Box>
);
};

export default CenterdSpinner;
export default CenteredSpinner;
5 changes: 3 additions & 2 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ const Header = () => {
<img
className="header-img"
src="./bookfinderlogo.svg"
alt="Book Finder Header"
></img>
alt="Book Finder logo" // Simplified alt text
role="img" // Indicate that this is an image
/>
</header>
);
};
Expand Down
12 changes: 10 additions & 2 deletions src/components/Paginate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ const Paginate = ({ booksPerPage, totalBooks, paginate }) => {
for (let i = 1; i <= Math.ceil(totalBooks / booksPerPage); i++) {
pageNumber.push(i);
}

return (
<Box>
<Pagination count={pageNumber.length} onChange={(e, p) => paginate(p)} />
<Box
role="navigation" // Indicate that this is a navigation section
aria-label="Pagination controls" // Provide a label for the navigation
>
<Pagination
count={pageNumber.length}
onChange={(e, p) => paginate(p)}
aria-label="Page navigation" // Provide an accessible label for pagination
/>
</Box>
);
};
Expand Down