Checkbox
Square checkbox.
Code
Copy into src/components/ph/ .
checkbox.css
.ph-checkbox {
appearance: none;
display: inline-grid;
place-content: center;
width: 16px;
height: 16px;
margin: 0;
flex: none;
border: 1px solid var(--foreground);
border-radius: 0;
background: var(--background);
cursor: pointer;
}
.ph-checkbox::before {
content: "";
width: 12px;
height: 12px;
background: var(--background);
-webkit-mask: var(--ph-check) center / contain no-repeat;
mask: var(--ph-check) center / contain no-repeat;
opacity: 0;
}
.ph-checkbox:checked {
background: var(--foreground);
}
.ph-checkbox:checked::before {
opacity: 1;
}
.ph-checkbox:disabled {
cursor: not-allowed;
opacity: 0.4;
}
.ph-checkbox {
--ph-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolygon points='22 4 22 6 21 6 21 7 20 7 20 8 19 8 19 9 18 9 18 10 17 10 17 11 16 11 16 12 15 12 15 13 14 13 14 14 13 14 13 15 12 15 12 16 11 16 11 17 10 17 10 18 8 18 8 17 7 17 7 16 6 16 6 15 5 15 5 14 4 14 4 13 3 13 3 12 2 12 2 10 4 10 4 11 5 11 5 12 6 12 6 13 7 13 7 14 8 14 8 15 10 15 10 14 11 14 11 13 12 13 12 12 13 12 13 11 14 11 14 10 15 10 15 9 16 9 16 8 17 8 17 7 18 7 18 6 19 6 19 5 20 5 20 4 22 4'/%3E%3C/svg%3E");
}
Checkbox.astro
---
import type { HTMLAttributes } from "astro/types";
import "./checkbox.css";
type Props = Omit<HTMLAttributes<"input">, "type">;
const { class: className, ...rest } = Astro.props;
---
<label class:list={["inline-flex cursor-pointer items-center gap-2 leading-[1.35]", className]}>
<input type="checkbox" class="ph-checkbox" {...rest} />
<slot />
</label>
Copy into components/ph/ (or src/components/ph/).
checkbox.css
.ph-checkbox {
appearance: none;
display: inline-grid;
place-content: center;
width: 16px;
height: 16px;
margin: 0;
flex: none;
border: 1px solid var(--foreground);
border-radius: 0;
background: var(--background);
cursor: pointer;
}
.ph-checkbox::before {
content: "";
width: 12px;
height: 12px;
background: var(--background);
-webkit-mask: var(--ph-check) center / contain no-repeat;
mask: var(--ph-check) center / contain no-repeat;
opacity: 0;
}
.ph-checkbox:checked {
background: var(--foreground);
}
.ph-checkbox:checked::before {
opacity: 1;
}
.ph-checkbox:disabled {
cursor: not-allowed;
opacity: 0.4;
}
.ph-checkbox {
--ph-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolygon points='22 4 22 6 21 6 21 7 20 7 20 8 19 8 19 9 18 9 18 10 17 10 17 11 16 11 16 12 15 12 15 13 14 13 14 14 13 14 13 15 12 15 12 16 11 16 11 17 10 17 10 18 8 18 8 17 7 17 7 16 6 16 6 15 5 15 5 14 4 14 4 13 3 13 3 12 2 12 2 10 4 10 4 11 5 11 5 12 6 12 6 13 7 13 7 14 8 14 8 15 10 15 10 14 11 14 11 13 12 13 12 12 13 12 13 11 14 11 14 10 15 10 15 9 16 9 16 8 17 8 17 7 18 7 18 6 19 6 19 5 20 5 20 4 22 4'/%3E%3C/svg%3E");
}
checkbox.tsx
import type { InputHTMLAttributes, ReactNode } from "react";
import { cn } from "./cn";
import "./checkbox.css";
type CheckboxProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type"> & {
children?: ReactNode;
};
export function Checkbox({ children, className, ...rest }: CheckboxProps) {
return (
<label className={cn("inline-flex cursor-pointer items-center gap-2 leading-[1.35]", className)}>
<input type="checkbox" className="ph-checkbox" {...rest} />
{children}
</label>
);
}
cn.ts
export const cn = (...parts: (string | false | null | undefined)[]) => parts.filter(Boolean).join(" ");