WIDGETS

Sudoku Widget

Click To Go Back To The Widgets Page

Preview

About

This is a web sudoku widget that fastly generates a random sudoku puzzle for guests.

  • To play it, click on a cell and press a number on your keyboard (or use the number pad on the widget).
  • To set a number on a cell, press a number once.
  • To leave a mark on a cell, press the same number twice or add a different number.
  • To remove a mark or turn a single mark into a number, press the target number on your keyboard.
  • To clear a cell, press Backspace or Delete button on your keyboard.
  • You can also use arrow keys or tab button to move the cell cursor.


Version: 1.0, File Size: 21.33KB



How To Add?

By hotlinking:

Put this script on your HTML document.

<script src="https://404city.neocities.org/widget/sudoku.js" data-difficulty="random" data-symmetrical="true"></script>
By uploading on your site (Recommended):

Click here to download the script. Then, upload it on your site and put this line on your HTML document.

<script src="YOUR_SCRIPT_PATH_HERE" data-difficulty="random" data-symmetrical="true"></script>
  • Make sure the script is located after <body> but before </body>.
  • The sudoku will instantly pop-up where you put the script.

Script Attributes:

Here are the script attributes of the sudoku widget.

AttributeConditions
data-difficulty easy => generates an easy level sudoku. A random number of cells between 36 and 45 are revealed.
medium => generates a medium level sudoku. A random number of cells between 30 and 35 are revealed.
hard => generates a hard level sudoku. A random number of cells between 26 and 30 are revealed.
expert => generates an expert level sudoku. A random number of cells between 22 and 26 are revealed.
random => generates a random level sudoku.
data-symmetrical true => generates a symmetrical number layout. Makes generation process faster and puzzle looks better.
false => generates a random number layout.

ID, Class and Variable Information:

Here are the ID, Class and Variable selectors of the sudoku widget's elements. You can use them on your own CSS file to customize your sudoku widget.

ID/Class/VariableElement TypeDescription
#sudokudivMain body of the sudoku widget.
#sudokuTextspanShows the current status of the puzzle and displays checking messages.
#sudokuGriddivContains every sudoku cell.
.sudokuCelldivGeneral class for each sudoku cell.
.sudokuCell::beforepseudo-elementDisplays cell numbers.
.sudokuCell[data-readonlycell="false"]divSelector for editable cells.
.sudokuCell[data-readonlycell="true"]divSelector for uneditable cells.
.sudokuCell:focusdivMarks the chosen cell (acts as a cursor).
--numericalHintBackgrounddefined in .sudokuCellBackground mark variable for the same numbers with the chosen cell's number.
--numericalHintColordefined in .sudokuCellColor mark variable for the same numbers with the chosen cell's number.
.sudokuMistakeHighlightdivMarks incorrect cells after checking.
.sudokuMarkdivEach number marks in the cells.
#sudokuNumButtonPaddivContainer of number entry buttons.
.sudokuNumButtonbuttonEach number entry button of the sudoku.
#sudokuFooterdivWrapper of time display and control buttons.
#sudokuTimespanDisplays game time.
.sudokuButtonbuttonGeneral class for the sudoku's control buttons.
#sudokuCheckButtonbuttonChecks the puzzle when clicked.
#sudokuRevealButtonbuttonReveals the chosen cell when clicked.
#sudokuResetButtonbuttonRestarts the game when clicked.
#sudokuNewButtonbuttonGenerates a new random puzzle when clicked.

Default CSS Rules

These are the default CSS selectors that are automatically generated and applied by the script:

:where(#sudoku, #sudoku *) {margin: 0; padding: 0; box-sizing: border-box;} :where(#sudoku) { height: 330px; width: 260px; display: flex; flex-direction: column; justify-content: center; align-items: center; font-family: Arial, Helvetica, sans-serif; font-size: 16px; padding: 0.25em; gap: 0.25rem; border: 1px solid #000; } :where(#sudokuGrid) { display: grid; grid-template-columns: repeat(9, 1fr); width: 100%; border: 1px solid #000; border-right: none; border-bottom: none; } :where(.sudokuCell) { --numericalHintBackground: #0ff; --numericalHintColor: #000; width: 100%; height: 100%; min-width: 0; aspect-ratio: 1 / 1; display: flex; justify-content: center; align-items: center; cursor: cell; border: none; border-right: 1px dotted #000; border-bottom: 1px dotted #000; :where(&:nth-child(3n)) {border-right-style: solid;} :where(&:nth-child(n + 19):nth-child(-n + 27), &:nth-child(n + 46):nth-child(-n + 54), &:nth-child(n + 73):nth-child(-n + 81)) {border-bottom-style: solid;} :where(&[data-readonlycell="true"]) { font-weight: bold; user-select: none; } :where(.sudokuMark) { display: none !important; visibility: hidden !important; line-height: 0.5; font-size: 10px; pointer-events: none; user-select: none; place-self: center; width: 100%; height: 100%; justify-content: center; align-items: center; text-align: center; letter-spacing: 0.125rem; } :where(&[data-cellmark="0"]:not([data-cellvalue="0"]))::before {content: attr(data-cellvalue);} :where(&:not([data-cellmark="0"])) { display: grid !important; grid-template-columns: repeat(3, 1fr); :where(.sudokuMark) {display: flex !important;} } :where(&[data-cellmark*="1"] .sudokuMark:nth-child(1), &[data-cellmark*="2"] .sudokuMark:nth-child(2), &[data-cellmark*="3"] .sudokuMark:nth-child(3), &[data-cellmark*="4"] .sudokuMark:nth-child(4), &[data-cellmark*="5"] .sudokuMark:nth-child(5), &[data-cellmark*="6"] .sudokuMark:nth-child(6), &[data-cellmark*="7"] .sudokuMark:nth-child(7), &[data-cellmark*="8"] .sudokuMark:nth-child(8), &[data-cellmark*="9"] .sudokuMark:nth-child(9)) {visibility: visible !important;} :where(#sudoku:has(&[data-cellvalue="1"]:focus) &[data-cellvalue="1"], #sudoku:has(&[data-cellvalue="1"]:focus) &[data-cellmark*="1"] .sudokuMark:nth-child(1), #sudoku:has(&[data-cellvalue="2"]:focus) &[data-cellvalue="2"], #sudoku:has(&[data-cellvalue="2"]:focus) &[data-cellmark*="2"] .sudokuMark:nth-child(2), #sudoku:has(&[data-cellvalue="3"]:focus) &[data-cellvalue="3"], #sudoku:has(&[data-cellvalue="3"]:focus) &[data-cellmark*="3"] .sudokuMark:nth-child(3), #sudoku:has(&[data-cellvalue="4"]:focus) &[data-cellvalue="4"], #sudoku:has(&[data-cellvalue="4"]:focus) &[data-cellmark*="4"] .sudokuMark:nth-child(4), #sudoku:has(&[data-cellvalue="5"]:focus) &[data-cellvalue="5"], #sudoku:has(&[data-cellvalue="5"]:focus) &[data-cellmark*="5"] .sudokuMark:nth-child(5), #sudoku:has(&[data-cellvalue="6"]:focus) &[data-cellvalue="6"], #sudoku:has(&[data-cellvalue="6"]:focus) &[data-cellmark*="6"] .sudokuMark:nth-child(6), #sudoku:has(&[data-cellvalue="7"]:focus) &[data-cellvalue="7"], #sudoku:has(&[data-cellvalue="7"]:focus) &[data-cellmark*="7"] .sudokuMark:nth-child(7), #sudoku:has(&[data-cellvalue="8"]:focus) &[data-cellvalue="8"], #sudoku:has(&[data-cellvalue="8"]:focus) &[data-cellmark*="8"] .sudokuMark:nth-child(8), #sudoku:has(&[data-cellvalue="9"]:focus) &[data-cellvalue="9"], #sudoku:has(&[data-cellvalue="9"]:focus) &[data-cellmark*="9"] .sudokuMark:nth-child(9)) { background: var(--numericalHintBackground); color: var(--numericalHintColor); } :where(&:focus) { outline: none; background: #00f; color: #fff; } :where(&.sudokuMistakeHighlight) { color: #fff; background: #f00; } } :where(#sudokuText) { font-size: 14px; user-select: none; margin-bottom: -0.125rem; &.sudokuTextBlink {animation: sudokuTextBlink 1s steps(1) infinite;} } @keyframes sudokuTextBlink {50% {visibility: hidden;}} :where(#sudokuNumButtonPad) { display: flex; width: 100%; border: 1px solid #000; border-right: none; } :where(.sudokuNumButton) { appearance: none; border: none; border-right: 1px solid #000; background: #0000; font-size: 1em; cursor: pointer; flex: 1; aspect-ratio: 1 / 1; box-sizing: content-box; } :where(#sudokuFooter) { width: 100%; display: flex; align-items: center; font-size: 14px; gap: 0.25rem; } :where(#sudokuTime) { flex: 1; user-select: none; } :where(.sudokuButton) { appearance: none; font-size: 1em; border: 1px solid #000; background: none; padding: 0 0.125rem; cursor: pointer; }

HTML Structure

The HTML code that is automatically generated by the script:

<div id='sudoku'> <span id="sudokuText">Loading...</span> <div id='sudokuGrid'> <div class="sudokuCell" tabindex="0" data-cellrow="#" data-cellcol="#" data-cellvalue="#" data-cellmark="#" data-readonlycell="#"> ::before <div class="sudokuMark">1</div> <div class="sudokuMark">2</div> <div class="sudokuMark">3</div> <div class="sudokuMark">4</div> <div class="sudokuMark">5</div> <div class="sudokuMark">6</div> <div class="sudokuMark">7</div> <div class="sudokuMark">8</div> <div class="sudokuMark">9</div> </div> . . . (81 sudoku cells in total.) . . . <div class="sudokuCell" tabindex="0" data-cellrow="#" data-cellcol="#" data-cellvalue="#" data-cellmark="#" data-readonlycell="#"> . . . </div> </div> <div id="sudokuNumButtonPad"> <button class="sudokuNumButton" data-numbuttonvalue="1">1</button> <button class="sudokuNumButton" data-numbuttonvalue="2">2</button> <button class="sudokuNumButton" data-numbuttonvalue="3">3</button> <button class="sudokuNumButton" data-numbuttonvalue="4">4</button> <button class="sudokuNumButton" data-numbuttonvalue="5">5</button> <button class="sudokuNumButton" data-numbuttonvalue="6">6</button> <button class="sudokuNumButton" data-numbuttonvalue="7">7</button> <button class="sudokuNumButton" data-numbuttonvalue="8">8</button> <button class="sudokuNumButton" data-numbuttonvalue="9">9</button> <button class="sudokuNumButton" data-numbuttonvalue="Delete">X</button> </div> <div id="sudokuFooter"> <span id="sudokuTime"><u>Time</u>:0</span> <button id="sudokuCheckButton" class="sudokuButton">Check</button> <button id="sudokuRevealButton" class="sudokuButton">Reveal</button> <button id="sudokuResetButton" class="sudokuButton">Reset</button> <button id="sudokuNewButton" class="sudokuButton">New</button> </div> </div>

Update Log

[v1.0] - 1 September 2026, Tuesday
  • Widget is ready to use!


Click To Go Back To The Widgets Page